aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-11-11 14:43:48 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2020-11-16 18:17:05 +0100
commit851704a761461270eae5b9aaf26711c5527bbc44 (patch)
tree127709ea943782dc04f91aabc9866abd16384fcf /ui
parentgo-patches: support 8 callback arguments on arm (diff)
downloadwireguard-windows-851704a761461270eae5b9aaf26711c5527bbc44.tar.xz
wireguard-windows-851704a761461270eae5b9aaf26711c5527bbc44.zip
ui: remove systray popup menu tunnel list
Should user have a huge list of tunnels, the menu becomes impossible to navigate. In the absence of any better idea, how to make the popup menu usable in such tunnel quantities, the tunnel activation via systray popup menu was removed, and instead we have a single deactivate button. Signed-off-by: Simon Rozman <simon@rozman.si> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'ui')
-rw-r--r--ui/tray.go233
1 files changed, 55 insertions, 178 deletions
diff --git a/ui/tray.go b/ui/tray.go
index f1fb727e..37c3af25 100644
--- a/ui/tray.go
+++ b/ui/tray.go
@@ -6,41 +6,26 @@
package ui
import (
- "sort"
"strings"
"time"
- "golang.zx2c4.com/wireguard/windows/conf"
"golang.zx2c4.com/wireguard/windows/l18n"
"golang.zx2c4.com/wireguard/windows/manager"
"github.com/lxn/walk"
)
-// Status + active CIDRs + separator
-const trayTunnelActionsOffset = 3
-
type Tray struct {
*walk.NotifyIcon
-
- // Current known tunnels by name
- tunnels map[string]*walk.Action
-
- mtw *ManageTunnelsWindow
-
- tunnelChangedCB *manager.TunnelChangeCallback
- tunnelsChangedCB *manager.TunnelsChangeCallback
-
- clicked func()
+ mtw *ManageTunnelsWindow
+ tunnelChangedCB *manager.TunnelChangeCallback
+ clicked func()
}
func NewTray(mtw *ManageTunnelsWindow) (*Tray, error) {
var err error
- tray := &Tray{
- mtw: mtw,
- tunnels: make(map[string]*walk.Action),
- }
+ tray := &Tray{mtw: mtw}
tray.NotifyIcon, err = walk.NewNotifyIcon(mtw)
if err != nil {
@@ -78,6 +63,7 @@ func (tray *Tray) setup() error {
}{
{label: l18n.Sprintf("Status: Unknown")},
{label: l18n.Sprintf("Addresses: None"), hidden: true},
+ {label: l18n.Sprintf("&Deactivate"), handler: tray.onDeactivateTunnel, enabled: true, hidden: true},
{separator: true},
{separator: true},
{label: l18n.Sprintf("&Manage tunnels…"), handler: tray.onManageTunnels, enabled: true, defawlt: true},
@@ -103,8 +89,6 @@ func (tray *Tray) setup() error {
tray.ContextMenu().Actions().Add(action)
}
tray.tunnelChangedCB = manager.IPCClientRegisterTunnelChange(tray.onTunnelChange)
- tray.tunnelsChangedCB = manager.IPCClientRegisterTunnelsChange(tray.onTunnelsChange)
- tray.onTunnelsChange()
globalState, _ := manager.IPCClientGlobalState()
tray.updateGlobalState(globalState)
@@ -116,103 +100,23 @@ func (tray *Tray) Dispose() error {
tray.tunnelChangedCB.Unregister()
tray.tunnelChangedCB = nil
}
- if tray.tunnelsChangedCB != nil {
- tray.tunnelsChangedCB.Unregister()
- tray.tunnelsChangedCB = nil
- }
return tray.NotifyIcon.Dispose()
}
-func (tray *Tray) onTunnelsChange() {
- tunnels, err := manager.IPCClientTunnels()
- if err != nil {
- return
- }
- tray.mtw.Synchronize(func() {
- tunnelSet := make(map[string]bool, len(tunnels))
- for _, tunnel := range tunnels {
- tunnelSet[tunnel.Name] = true
- if tray.tunnels[tunnel.Name] == nil {
- tray.addTunnelAction(&tunnel)
- }
- }
- for trayTunnel := range tray.tunnels {
- if !tunnelSet[trayTunnel] {
- tray.removeTunnelAction(trayTunnel)
- }
- }
- })
-}
-
-func (tray *Tray) addTunnelAction(tunnel *manager.Tunnel) {
- tunnelAction := walk.NewAction()
- tunnelAction.SetText(tunnel.Name)
- tunnelAction.SetEnabled(true)
- tunnelAction.SetCheckable(true)
- tclosure := *tunnel
- tunnelAction.Triggered().Attach(func() {
- tunnelAction.SetChecked(!tunnelAction.Checked())
- go func() {
- oldState, err := tclosure.Toggle()
- if err != nil {
- tray.mtw.Synchronize(func() {
- raise(tray.mtw.Handle())
- tray.mtw.tunnelsPage.listView.selectTunnel(tclosure.Name)
- tray.mtw.tabs.SetCurrentIndex(0)
- if oldState == manager.TunnelUnknown {
- showErrorCustom(tray.mtw, l18n.Sprintf("Failed to determine tunnel state"), err.Error())
- } else if oldState == manager.TunnelStopped {
- showErrorCustom(tray.mtw, l18n.Sprintf("Failed to activate tunnel"), err.Error())
- } else if oldState == manager.TunnelStarted {
- showErrorCustom(tray.mtw, l18n.Sprintf("Failed to deactivate tunnel"), err.Error())
- }
- })
- }
- }()
- })
- tray.tunnels[tunnel.Name] = tunnelAction
-
- var names []string
- for name := range tray.tunnels {
- names = append(names, name)
- }
- sort.SliceStable(names, func(i, j int) bool {
- return conf.TunnelNameIsLess(names[i], names[j])
- })
-
- var (
- idx int
- name string
- )
- for idx, name = range names {
- if name == tunnel.Name {
- break
- }
- }
-
- tray.ContextMenu().Actions().Insert(trayTunnelActionsOffset+idx, tunnelAction)
-
- go func() {
- state, err := tclosure.State()
- if err != nil {
- return
- }
- tray.mtw.Synchronize(func() {
- tray.SetTunnelState(&tclosure, state, false)
- })
- }()
-}
-
-func (tray *Tray) removeTunnelAction(tunnelName string) {
- tray.ContextMenu().Actions().Remove(tray.tunnels[tunnelName])
- delete(tray.tunnels, tunnelName)
-}
-
func (tray *Tray) onTunnelChange(tunnel *manager.Tunnel, state manager.TunnelState, globalState manager.TunnelState, err error) {
tray.mtw.Synchronize(func() {
tray.updateGlobalState(globalState)
- tray.SetTunnelState(tunnel, state, err == nil)
- if !tray.mtw.Visible() && err != nil {
+ if err == nil {
+ switch state {
+ case manager.TunnelStarted:
+ icon, _ := iconWithOverlayForState(state, 128)
+ tray.ShowCustom(l18n.Sprintf("WireGuard Activated"), l18n.Sprintf("The %s tunnel has been activated.", tunnel.Name), icon)
+
+ case manager.TunnelStopped:
+ icon, _ := loadSystemIcon("imageres", 26, 128) // TODO: this icon isn't very good...
+ tray.ShowCustom(l18n.Sprintf("WireGuard Deactivated"), l18n.Sprintf("The %s tunnel has been deactivated.", tunnel.Name), icon)
+ }
+ } else if !tray.mtw.Visible() {
tray.ShowError(l18n.Sprintf("WireGuard Tunnel Error"), err.Error())
}
})
@@ -225,80 +129,34 @@ func (tray *Tray) updateGlobalState(globalState manager.TunnelState) {
actions := tray.ContextMenu().Actions()
statusAction := actions.At(0)
- activeCIDRsAction := actions.At(1)
-
- setTunnelActionsEnabled := func(enabled bool) {
- for i := 0; i < len(tray.tunnels); i++ {
- action := actions.At(trayTunnelActionsOffset + i)
- action.SetEnabled(enabled)
- }
- }
+ deactivateTunnelAction := actions.At(2)
tray.SetToolTip(l18n.Sprintf("WireGuard: %s", textForState(globalState, true)))
stateText := textForState(globalState, false)
statusAction.SetText(l18n.Sprintf("Status: %s", stateText))
-
- switch globalState {
- case manager.TunnelStarting:
- setTunnelActionsEnabled(false)
-
- case manager.TunnelStarted:
- activeCIDRsAction.SetVisible(true)
- setTunnelActionsEnabled(true)
-
- case manager.TunnelStopping:
- setTunnelActionsEnabled(false)
-
- case manager.TunnelStopped:
- activeCIDRsAction.SetVisible(false)
- setTunnelActionsEnabled(true)
- }
-}
-
-func (tray *Tray) SetTunnelState(tunnel *manager.Tunnel, state manager.TunnelState, showNotifications bool) {
- tunnelAction := tray.tunnels[tunnel.Name]
- if tunnelAction == nil {
- return
- }
-
- actions := tray.ContextMenu().Actions()
- activeCIDRsAction := actions.At(1)
-
- wasChecked := tunnelAction.Checked()
-
- switch state {
- case manager.TunnelStarted:
- activeCIDRsAction.SetText("")
- go func() {
- config, err := tunnel.RuntimeConfig()
- if err == nil {
- var sb strings.Builder
- for i, addr := range config.Interface.Addresses {
- if i > 0 {
- sb.WriteString(l18n.EnumerationSeparator())
+ deactivateTunnelAction.SetVisible(globalState == manager.TunnelStarted)
+ go func() {
+ var addrs []string
+ tunnels, err := manager.IPCClientTunnels()
+ if err == nil {
+ for i := range tunnels {
+ state, err := tunnels[i].State()
+ if err == nil && state == manager.TunnelStarted {
+ config, err := tunnels[i].RuntimeConfig()
+ if err == nil {
+ for _, addr := range config.Interface.Addresses {
+ addrs = append(addrs, addr.String())
+ }
}
-
- sb.WriteString(addr.String())
}
- tray.mtw.Synchronize(func() {
- activeCIDRsAction.SetText(l18n.Sprintf("Addresses: %s", sb.String()))
- })
}
- }()
- tunnelAction.SetEnabled(true)
- tunnelAction.SetChecked(true)
- if !wasChecked && showNotifications {
- icon, _ := iconWithOverlayForState(state, 128)
- tray.ShowCustom(l18n.Sprintf("WireGuard Activated"), l18n.Sprintf("The %s tunnel has been activated.", tunnel.Name), icon)
}
-
- case manager.TunnelStopped:
- tunnelAction.SetChecked(false)
- if wasChecked && showNotifications {
- icon, _ := loadSystemIcon("imageres", 26, 128) // TODO: this icon isn't very good...
- tray.ShowCustom(l18n.Sprintf("WireGuard Deactivated"), l18n.Sprintf("The %s tunnel has been deactivated.", tunnel.Name), icon)
- }
- }
+ tray.mtw.Synchronize(func() {
+ activeCIDRsAction := tray.ContextMenu().Actions().At(1)
+ activeCIDRsAction.SetText(l18n.Sprintf("Addresses: %s", strings.Join(addrs, l18n.EnumerationSeparator())))
+ activeCIDRsAction.SetVisible(len(addrs) > 0)
+ })
+ }()
}
func (tray *Tray) UpdateFound() {
@@ -333,6 +191,25 @@ func (tray *Tray) UpdateFound() {
}
}
+func (tray *Tray) onDeactivateTunnel() {
+ go func() {
+ tunnels, err := manager.IPCClientTunnels()
+ if err == nil {
+ for i := range tunnels {
+ state, err := tunnels[i].State()
+ if err == nil && state != manager.TunnelStopped {
+ err = tunnels[i].Stop()
+ }
+ }
+ }
+ if err != nil {
+ tray.mtw.Synchronize(func() {
+ showErrorCustom(tray.mtw, l18n.Sprintf("Failed to deactivate tunnel"), err.Error())
+ })
+ }
+ }()
+}
+
func (tray *Tray) onManageTunnels() {
tray.mtw.tunnelsPage.listView.SelectFirstActiveTunnel()
tray.mtw.tabs.SetCurrentIndex(0)