aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/iconprovider.go
blob: e26479394f50c8557149b998154264e5a4fa0e46 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/* SPDX-License-Identifier: MIT
 *
 * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
 */

package ui

import (
	"fmt"
	"github.com/lxn/walk"
	"github.com/lxn/win"
	"golang.org/x/sys/windows"
	"golang.zx2c4.com/wireguard/windows/service"
	"path"
)

func iconWithOverlayForState(state service.TunnelState, size int) (*walk.Icon, error) {
	wireguardIcon, err := walk.NewIconFromResourceWithSize("$wireguard.ico", walk.Size{size, size})
	if err != nil {
		return nil, err
	}
	defer wireguardIcon.Dispose()
	iconSize := wireguardIcon.Size()
	bmp, err := walk.NewBitmapWithTransparentPixels(iconSize)
	if err != nil {
		return nil, err
	}
	defer bmp.Dispose()

	canvas, err := walk.NewCanvasFromImage(bmp)
	if err != nil {
		return nil, err
	}
	defer canvas.Dispose()

	if err := canvas.DrawImage(wireguardIcon, walk.Point{}); err != nil {
		return nil, err
	}

	w := int(float64(iconSize.Width) * 0.65)
	h := int(float64(iconSize.Height) * 0.65)
	bounds := walk.Rectangle{iconSize.Width - w, iconSize.Height - h, w, h}
	overlayIcon, err := iconForState(state, bounds.Width)
	if err != nil {
		return nil, err
	}
	defer overlayIcon.Dispose()
	if err := canvas.DrawImageStretched(overlayIcon, bounds); err != nil {
		return nil, err
	}
	canvas.Dispose()

	icon, err := walk.NewIconFromBitmap(bmp)
	if err != nil {
		return nil, err
	}
	return icon, nil
}

func iconForState(state service.TunnelState, size int) (icon *walk.Icon, err error) {
	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
	}
	return
}

func loadSystemIcon(dll string, index int32, size int) (*walk.Icon, error) {
	system32, err := windows.GetSystemDirectory()
	if err != nil {
		return nil, err
	}
	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 walk.NewIconFromHICON(hicon)
}