aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-05-08 11:52:18 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-08 12:16:49 +0200
commit4835f350ffe6b4fa589748e808fb84cc7c53e103 (patch)
treee0a3488aa1447bd741735037a9b347963b428d1d /ui
parentinstaller: smarter detection of SYSTEM profile folder (diff)
downloadwireguard-windows-4835f350ffe6b4fa589748e808fb84cc7c53e103.tar.xz
wireguard-windows-4835f350ffe6b4fa589748e808fb84cc7c53e103.zip
ui: get correctly sized system iconsv0.0.1
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'ui')
-rw-r--r--ui/aboutdialog.go5
-rw-r--r--ui/confview.go24
-rw-r--r--ui/iconprovider.go69
-rw-r--r--ui/listview.go2
-rw-r--r--ui/managewindow.go7
-rw-r--r--ui/tray.go24
-rw-r--r--ui/tunnelspage.go10
-rw-r--r--ui/ui.go5
-rw-r--r--ui/updatepage.go9
9 files changed, 71 insertions, 84 deletions
diff --git a/ui/aboutdialog.go b/ui/aboutdialog.go
index da8f7f9f..22148ac1 100644
--- a/ui/aboutdialog.go
+++ b/ui/aboutdialog.go
@@ -25,7 +25,10 @@ func onAbout(owner walk.Form) {
dlg, _ := walk.NewDialogWithFixedSize(owner)
dlg.SetTitle("About WireGuard")
dlg.SetLayout(vbl)
- dlg.SetIcon(iconProvider.wireguardIcon)
+ wireguardIcon, err := walk.NewIconFromResourceWithSize("$wireguard.ico", walk.Size{dlg.DPI()/3, dlg.DPI()/3}) //TODO: calculate DPI dynamically
+ if err == nil {
+ dlg.SetIcon(wireguardIcon)
+ }
font, _ := walk.NewFont("Segoe UI", 9, 0)
dlg.SetFont(font)
diff --git a/ui/confview.go b/ui/confview.go
index 515cadde..dbbe0ab4 100644
--- a/ui/confview.go
+++ b/ui/confview.go
@@ -79,17 +79,17 @@ func (lsl *labelStatusLine) widgets() (walk.Widget, walk.Widget) {
}
func (lsl *labelStatusLine) update(state service.TunnelState) {
- icon, err := iconProvider.IconForState(state)
+ margin := lsl.label.DPI() / 48 //TODO: Do some sort of dynamic DPI calculation here
+ labelSize := lsl.label.SizeHint()
+ imageRect := walk.Rectangle{0, 0, labelSize.Height, labelSize.Height}
+ img, _ := walk.NewBitmapWithTransparentPixels(imageRect.Size())
+ canvas, _ := walk.NewCanvasFromImage(img)
+ imageRect.X += margin
+ imageRect.Y += margin * 2 //TODO: the *2 here fixes weird alignment bugs. Why?
+ imageRect.Height -= margin * 2
+ imageRect.Width -= margin * 2
+ icon, err := iconForState(state, imageRect.Size().Width)
if err == nil {
- margin := lsl.label.DPI() / 48 //TODO: Do some sort of dynamic DPI calculation here
- labelSize := lsl.label.SizeHint()
- imageRect := walk.Rectangle{0, 0, labelSize.Height, labelSize.Height}
- img, _ := walk.NewBitmapWithTransparentPixels(imageRect.Size())
- canvas, _ := walk.NewCanvasFromImage(img)
- imageRect.X += margin
- imageRect.Y += margin * 2 //TODO: the *2 here fixes weird alignment bugs. Why?
- imageRect.Height -= margin * 2
- imageRect.Width -= margin * 2
canvas.DrawImageStretched(icon, imageRect)
icon.Dispose()
canvas.Dispose()
@@ -99,7 +99,11 @@ func (lsl *labelStatusLine) update(state service.TunnelState) {
prior.Dispose()
}
} else {
+ prior := lsl.statusImage.Image()
lsl.statusImage.SetImage(nil)
+ if prior != nil {
+ prior.Dispose()
+ }
}
s, e := lsl.statusLabel.TextSelection()
switch state {
diff --git a/ui/iconprovider.go b/ui/iconprovider.go
index ac373d90..e2647939 100644
--- a/ui/iconprovider.go
+++ b/ui/iconprovider.go
@@ -14,41 +14,14 @@ import (
"path"
)
-type IconProvider struct {
- wireguardIcon *walk.Icon
- overlayIconsByState map[service.TunnelState]*walk.Icon
-}
-
-func NewIconProvider() (*IconProvider, error) {
- tsip := &IconProvider{overlayIconsByState: make(map[service.TunnelState]*walk.Icon)}
- var err error
- if tsip.wireguardIcon, err = walk.NewIconFromResource("$wireguard.ico"); err != nil {
+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
}
- return tsip, nil
-}
-
-func (tsip *IconProvider) Dispose() {
- if tsip.overlayIconsByState != nil {
- for _, icon := range tsip.overlayIconsByState {
- icon.Dispose()
- }
- tsip.overlayIconsByState = nil
- }
- if tsip.wireguardIcon != nil {
- tsip.wireguardIcon.Dispose()
- tsip.wireguardIcon = nil
- }
-}
-
-func (tsip *IconProvider) IconWithOverlayForState(state service.TunnelState) (*walk.Icon, error) {
- if icon, ok := tsip.overlayIconsByState[state]; ok {
- return icon, nil
- }
-
- size := tsip.wireguardIcon.Size()
-
- bmp, err := walk.NewBitmapWithTransparentPixels(size)
+ defer wireguardIcon.Dispose()
+ iconSize := wireguardIcon.Size()
+ bmp, err := walk.NewBitmapWithTransparentPixels(iconSize)
if err != nil {
return nil, err
}
@@ -60,20 +33,18 @@ func (tsip *IconProvider) IconWithOverlayForState(state service.TunnelState) (*w
}
defer canvas.Dispose()
- if err := canvas.DrawImage(tsip.wireguardIcon, walk.Point{}); err != nil {
+ if err := canvas.DrawImage(wireguardIcon, walk.Point{}); err != nil {
return nil, err
}
- overlayIcon, err := tsip.IconForState(state)
+ 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()
-
- w := int(float64(size.Width) * 0.65)
- h := int(float64(size.Height) * 0.65)
- bounds := walk.Rectangle{size.Width - w, size.Height - h, w, h}
-
if err := canvas.DrawImageStretched(overlayIcon, bounds); err != nil {
return nil, err
}
@@ -83,32 +54,32 @@ func (tsip *IconProvider) IconWithOverlayForState(state service.TunnelState) (*w
if err != nil {
return nil, err
}
- tsip.overlayIconsByState[state] = icon
return icon, nil
}
-func (tsip *IconProvider) IconForState(state service.TunnelState) (icon *walk.Icon, err error) {
+func iconForState(state service.TunnelState, size int) (icon *walk.Icon, err error) {
switch state {
case service.TunnelStarted:
- icon, err = loadSystemIcon("imageres", 101)
+ icon, err = loadSystemIcon("imageres", 101, size)
case service.TunnelStopped:
- icon, err = walk.NewIconFromResource("dot-gray.ico") //TODO: replace with real icon
+ icon, err = walk.NewIconFromResourceWithSize("dot-gray.ico", walk.Size{size, size}) //TODO: replace with real icon
default:
- icon, err = loadSystemIcon("shell32", 238) //TODO: this doesn't look that great overlayed on the app icon
+ icon, err = loadSystemIcon("shell32", 238, size) //TODO: this doesn't look that great overlayed on the app icon
}
return
}
-func loadSystemIcon(dll string, index uint) (*walk.Icon, error) {
+func loadSystemIcon(dll string, index int32, size int) (*walk.Icon, error) {
system32, err := windows.GetSystemDirectory()
if err != nil {
return nil, err
}
- hicon := win.ExtractIcon(win.GetModuleHandle(nil), windows.StringToUTF16Ptr(path.Join(system32, dll+".dll")), int32(index))
- if hicon <= 1 {
- return nil, fmt.Errorf("Unable to find icon %d of %s", index, dll)
+ 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)
}
diff --git a/ui/listview.go b/ui/listview.go
index 814a799b..0a15c5da 100644
--- a/ui/listview.go
+++ b/ui/listview.go
@@ -132,7 +132,7 @@ func (tv *ListView) StyleCell(style *walk.CellStyle) {
b.Y += margin
b.Height -= margin * 2
b.Width = b.Height
- icon, err := iconProvider.IconForState(state)
+ icon, err := iconForState(state, b.Size().Width)
if err != nil {
return
}
diff --git a/ui/managewindow.go b/ui/managewindow.go
index 6d8c9701..5b8279d9 100644
--- a/ui/managewindow.go
+++ b/ui/managewindow.go
@@ -36,7 +36,10 @@ func NewManageTunnelsWindow() (*ManageTunnelsWindow, error) {
}
disposables.Add(mtw)
- mtw.SetIcon(iconProvider.wireguardIcon)
+ wireguardIcon, err := walk.NewIconFromResourceWithSize("$wireguard.ico", walk.Size{mtw.DPI()/3, mtw.DPI()/3}) //TODO: calculate DPI dynamically
+ if err == nil {
+ mtw.SetIcon(wireguardIcon)
+ }
mtw.SetTitle("WireGuard")
font, err := walk.NewFont("Segoe UI", 9, 0)
if err != nil {
@@ -94,7 +97,7 @@ func (mtw *ManageTunnelsWindow) Dispose() {
func (mtw *ManageTunnelsWindow) onTunnelChange(tunnel *service.Tunnel, state service.TunnelState, globalState service.TunnelState, err error) {
mtw.Synchronize(func() {
- icon, err2 := iconProvider.IconWithOverlayForState(globalState)
+ icon, err2 := iconWithOverlayForState(globalState, mtw.DPI()/3) //TODO: calculate DPI dynamically
if err2 == nil {
mtw.SetIcon(icon)
}
diff --git a/ui/tray.go b/ui/tray.go
index 10fb350e..3cf0f8bc 100644
--- a/ui/tray.go
+++ b/ui/tray.go
@@ -54,7 +54,10 @@ func (tray *Tray) setup() error {
tray.SetToolTip("WireGuard: Deactivated")
tray.SetVisible(true)
- tray.SetIcon(iconProvider.wireguardIcon)
+ wireguardIcon, err := walk.NewIconFromResourceWithSize("$wireguard.ico", walk.Size{tray.mtw.DPI() / 6, tray.mtw.DPI() / 6}) //TODO: calculate DPI dynamically
+ if err == nil {
+ tray.SetIcon(wireguardIcon)
+ }
tray.MouseDown().Attach(func(x, y int, button walk.MouseButton) {
if button == walk.LeftButton {
@@ -216,8 +219,12 @@ func (tray *Tray) onTunnelChange(tunnel *service.Tunnel, state service.TunnelSta
}
func (tray *Tray) updateGlobalState(globalState service.TunnelState) {
- if icon, err := iconProvider.IconWithOverlayForState(globalState); err == nil {
+ if icon, err := iconWithOverlayForState(globalState, tray.mtw.DPI()/6); err == nil { //TODO: calculate DPI dynamically
+ prior := tray.Icon()
tray.SetIcon(icon)
+ if prior != nil {
+ prior.Dispose()
+ }
}
actions := tray.ContextMenu().Actions()
@@ -286,14 +293,14 @@ func (tray *Tray) SetTunnelState(tunnel *service.Tunnel, state service.TunnelSta
tunnelAction.SetEnabled(true)
tunnelAction.SetChecked(true)
if !wasChecked && showNotifications {
- icon, _ := iconProvider.IconWithOverlayForState(state)
+ icon, _ := iconWithOverlayForState(state, tray.mtw.DPI()*4/3) //TODO: calculate dpi dynamically
tray.ShowCustom("WireGuard Activated", fmt.Sprintf("The %s tunnel has been activated.", tunnel.Name), icon)
}
case service.TunnelStopped:
tunnelAction.SetChecked(false)
if wasChecked && showNotifications {
- icon, _ := loadSystemIcon("imageres", 26) //TODO: this icon isn't very good...
+ icon, _ := loadSystemIcon("imageres", 26, tray.mtw.DPI()*4/3) //TODO: this icon isn't very good..., also calculate dpi dynamically
defer icon.Dispose()
tray.ShowCustom("WireGuard Deactivated", fmt.Sprintf("The %s tunnel has been deactivated.", tunnel.Name), icon)
}
@@ -303,8 +310,10 @@ func (tray *Tray) SetTunnelState(tunnel *service.Tunnel, state service.TunnelSta
func (tray *Tray) UpdateFound() {
action := walk.NewAction()
action.SetText("An Update is Available!")
- icon, _ := loadSystemIcon("imageres", 1)
- bitmap, _ := walk.NewBitmapFromIcon(icon, walk.Size{tray.mtw.DPI() / 6, tray.mtw.DPI() / 6}) //TODO: This should use dynamic DPI.
+ iconSize := tray.mtw.DPI() / 6 //TODO: This should use dynamic DPI.
+ menuIcon, _ := loadSystemIcon("imageres", 1, iconSize)
+ bitmap, _ := walk.NewBitmapFromIcon(menuIcon, walk.Size{iconSize, iconSize})
+ menuIcon.Dispose()
action.SetImage(bitmap)
action.SetDefault(true)
showUpdateTab := func() {
@@ -319,8 +328,9 @@ func (tray *Tray) UpdateFound() {
tray.ContextMenu().Actions().Insert(tray.ContextMenu().Actions().Len()-2, action)
showUpdateBalloon := func() {
+ icon, _ := loadSystemIcon("imageres", 1, tray.mtw.DPI()*4/3) //TODO: calculate DPI dynamically
tray.ShowCustom("WireGuard Update Available", "An update to WireGuard is now available. You are advised to update as soon as possible.", icon)
- defer icon.Dispose()
+ icon.Dispose()
}
timeSinceStart := time.Now().Sub(startTime)
diff --git a/ui/tunnelspage.go b/ui/tunnelspage.go
index de7560c4..4df9938b 100644
--- a/ui/tunnelspage.go
+++ b/ui/tunnelspage.go
@@ -127,7 +127,7 @@ func (tp *TunnelsPage) CreateToolbar() {
tp.AddDisposable(addMenu)
importAction := walk.NewAction()
importAction.SetText("Import tunnel(s) from file...")
- importActionIcon, _ := loadSystemIcon("imageres", 3)
+ importActionIcon, _ := loadSystemIcon("imageres", 3, imageSize.Width)
importActionImage, _ := walk.NewBitmapFromIcon(importActionIcon, imageSize)
importAction.SetImage(importActionImage)
importAction.SetShortcut(walk.Shortcut{walk.ModControl, walk.KeyO})
@@ -135,7 +135,7 @@ func (tp *TunnelsPage) CreateToolbar() {
importAction.Triggered().Attach(tp.onImport)
addAction := walk.NewAction()
addAction.SetText("Add empty tunnel...")
- addActionIcon, _ := loadSystemIcon("imageres", 2)
+ addActionIcon, _ := loadSystemIcon("imageres", 2, imageSize.Width)
addActionImage, _ := walk.NewBitmapFromIcon(addActionIcon, imageSize)
addAction.SetImage(addActionImage)
addAction.SetShortcut(walk.Shortcut{walk.ModControl, walk.KeyN})
@@ -143,7 +143,7 @@ func (tp *TunnelsPage) CreateToolbar() {
addMenu.Actions().Add(importAction)
addMenu.Actions().Add(addAction)
addMenuAction := walk.NewMenuAction(addMenu)
- addMenuActionIcon, _ := loadSystemIcon("shell32", 149)
+ addMenuActionIcon, _ := loadSystemIcon("shell32", 149, imageSize.Width)
addMenuActionImage, _ := walk.NewBitmapFromIcon(addMenuActionIcon, imageSize)
addMenuAction.SetImage(addMenuActionImage)
addMenuAction.SetText("Add Tunnel")
@@ -154,7 +154,7 @@ func (tp *TunnelsPage) CreateToolbar() {
tp.listToolbar.Actions().Add(walk.NewSeparatorAction())
deleteAction := walk.NewAction()
- deleteActionIcon, _ := loadSystemIcon("shell32", 131)
+ deleteActionIcon, _ := loadSystemIcon("shell32", 131, imageSize.Width)
deleteActionImage, _ := walk.NewBitmapFromIcon(deleteActionIcon, imageSize)
deleteAction.SetImage(deleteActionImage)
deleteAction.SetShortcut(walk.Shortcut{0, walk.KeyDelete})
@@ -164,7 +164,7 @@ func (tp *TunnelsPage) CreateToolbar() {
tp.listToolbar.Actions().Add(walk.NewSeparatorAction())
exportAction := walk.NewAction()
- exportActionIcon, _ := loadSystemIcon("imageres", 165) // Or "shell32", 45?
+ exportActionIcon, _ := loadSystemIcon("imageres", 165, imageSize.Width) // Or "shell32", 45?
exportActionImage, _ := walk.NewBitmapFromIcon(exportActionIcon, imageSize)
exportAction.SetImage(exportActionImage)
exportAction.SetToolTip("Export all tunnels to zip...")
diff --git a/ui/ui.go b/ui/ui.go
index c5fa03c6..b662f96d 100644
--- a/ui/ui.go
+++ b/ui/ui.go
@@ -14,8 +14,6 @@ import (
"time"
)
-var iconProvider *IconProvider
-
var shouldQuitManagerWhenExiting = false
var startTime = time.Now()
@@ -36,8 +34,6 @@ func RunUI() {
tray *Tray
)
- iconProvider, _ = NewIconProvider()
-
for mtw == nil {
mtw, err = NewManageTunnelsWindow()
if err != nil {
@@ -83,7 +79,6 @@ func RunUI() {
mtw.Run()
tray.Dispose()
mtw.Dispose()
- iconProvider.Dispose()
if shouldQuitManagerWhenExiting {
_, err := service.IPCClientQuit(true)
diff --git a/ui/updatepage.go b/ui/updatepage.go
index 8c01efe4..a5471e9f 100644
--- a/ui/updatepage.go
+++ b/ui/updatepage.go
@@ -26,9 +26,10 @@ func NewUpdatePage() (*UpdatePage, error) {
up.SetTitle("An Update is Available!")
- tabIcon, _ := loadSystemIcon("imageres", 1)
+ iconSize := up.DPI() / 6
+ tabIcon, _ := loadSystemIcon("imageres", 1, iconSize)
defer tabIcon.Dispose()
- bitmap, _ := walk.NewBitmapFromIcon(tabIcon, walk.Size{up.DPI() / 6, up.DPI() / 6}) //TODO: this should use dynamic DPI
+ bitmap, _ := walk.NewBitmapFromIcon(tabIcon, walk.Size{iconSize, iconSize}) //TODO: this should use dynamic DPI
up.SetImage(bitmap)
//TODO: make title bold
@@ -46,8 +47,8 @@ func NewUpdatePage() (*UpdatePage, error) {
bar.SetVisible(false)
button, _ := walk.NewPushButton(up)
- updateIcon, _ := loadSystemIcon("shell32", 46)
- button.SetImage(updateIcon) //TODO: the placement of this looks sort of weird
+ updateIcon, _ := loadSystemIcon("shell32", 46, bar.HeightPixels())
+ button.SetImage(updateIcon)
button.SetText("Update Now")
walk.NewVSpacer(up)