aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/tray.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ui/tray.go173
1 files changed, 108 insertions, 65 deletions
diff --git a/ui/tray.go b/ui/tray.go
index 2650530d..3204d861 100644
--- a/ui/tray.go
+++ b/ui/tray.go
@@ -14,8 +14,8 @@ import (
"golang.zx2c4.com/wireguard/windows/service"
)
-// Status + active CIDRs + deactivate + separator
-const trayTunnelActionsOffset = 4
+// Status + active CIDRs + separator
+const trayTunnelActionsOffset = 3
type Tray struct {
*walk.NotifyIcon
@@ -23,18 +23,20 @@ type Tray struct {
// Current known tunnels by name
tunnels map[string]*walk.Action
- mtw *ManageTunnelsWindow
- icon *walk.Icon
+ mtw *ManageTunnelsWindow
+
+ tunnelChangedCB *service.TunnelChangeCallback
+ tunnelsChangedCB *service.TunnelsChangeCallback
}
-func NewTray(mtw *ManageTunnelsWindow, icon *walk.Icon) (*Tray, error) {
+func NewTray(mtw *ManageTunnelsWindow) (*Tray, error) {
var err error
tray := &Tray{
mtw: mtw,
- icon: icon,
tunnels: make(map[string]*walk.Action),
}
+
tray.NotifyIcon, err = walk.NewNotifyIcon(mtw.MainWindow)
if err != nil {
return nil, err
@@ -46,7 +48,7 @@ func NewTray(mtw *ManageTunnelsWindow, icon *walk.Icon) (*Tray, error) {
func (tray *Tray) setup() error {
tray.SetToolTip("WireGuard: Deactivated")
tray.SetVisible(true)
- tray.SetIcon(tray.icon)
+ tray.SetIcon(iconProvider.baseIcon)
tray.MouseDown().Attach(func(x, y int, button walk.MouseButton) {
if button == walk.LeftButton {
@@ -64,7 +66,6 @@ func (tray *Tray) setup() error {
}{
{label: "Status: Unknown"},
{label: "Networks: None", hidden: true},
- {label: "Deactivate", handler: tray.onDeactivateTunnel, enabled: true, hidden: true},
{separator: true},
{separator: true},
{label: "&Manage tunnels...", handler: tray.mtw.Show, enabled: true},
@@ -88,54 +89,94 @@ func (tray *Tray) setup() error {
tray.ContextMenu().Actions().Add(action)
}
+ tray.tunnelChangedCB = service.IPCClientRegisterTunnelChange(tray.onTunnelChange)
+ tray.tunnelsChangedCB = service.IPCClientRegisterTunnelsChange(tray.onTunnelsChange)
+ tray.onTunnelsChange()
+ tray.updateGlobalState()
- tunnels, err := service.IPCClientTunnels()
- if err != nil {
- return err
- }
+ return nil
+}
- for _, tunnel := range tunnels {
- tray.addTunnelAction(tunnel.Name)
+func (tray *Tray) Dispose() error {
+ if tray.tunnelChangedCB != nil {
+ tray.tunnelChangedCB.Unregister()
+ tray.tunnelChangedCB = nil
}
+ if tray.tunnelsChangedCB != nil {
+ tray.tunnelsChangedCB.Unregister()
+ tray.tunnelsChangedCB = nil
+ }
+ return tray.NotifyIcon.Dispose()
+}
- tray.mtw.tunnelsPage.TunnelAdded().Attach(tray.addTunnelAction)
- tray.mtw.tunnelsPage.TunnelDeleted().Attach(tray.removeTunnelAction)
-
- return nil
+func (tray *Tray) onTunnelsChange() {
+ tunnels, err := service.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(tunnelName string) {
+func (tray *Tray) addTunnelAction(tunnel *service.Tunnel) {
tunnelAction := walk.NewAction()
- tunnelAction.SetText(tunnelName)
+ tunnelAction.SetText(tunnel.Name)
tunnelAction.SetEnabled(true)
tunnelAction.SetCheckable(true)
+ tclosure := *tunnel
tunnelAction.Triggered().Attach(func() {
- if activeTunnel := tray.mtw.tunnelsPage.tunnelTracker.activeTunnel; activeTunnel != nil && activeTunnel.Name == tunnelName {
- tray.onDeactivateTunnel()
- } else {
- tray.onActivateTunnel(tunnelName)
+ oldState, err := tclosure.Toggle()
+ if err != nil {
+ tray.mtw.Show()
+ //TODO: select tunnel that we're showing the error for in mtw
+ if oldState == service.TunnelUnknown {
+ walk.MsgBox(tray.mtw, "Failed to determine tunnel state", err.Error(), walk.MsgBoxIconError)
+ } else if oldState == service.TunnelStopped {
+ walk.MsgBox(tray.mtw, "Failed to activate tunnel", err.Error(), walk.MsgBoxIconError)
+ } else if oldState == service.TunnelStarted {
+ walk.MsgBox(tray.mtw, "Failed to deactivate tunnel", err.Error(), walk.MsgBoxIconError)
+ }
+ return
}
})
- tray.tunnels[tunnelName] = tunnelAction
+ tray.tunnels[tunnel.Name] = tunnelAction
// Add the action at the right spot
var names []string
- for name, _ := range tray.tunnels {
+ for name := range tray.tunnels {
names = append(names, name)
}
- sort.Strings(names)
+ sort.Strings(names) //TODO: use correct sorting order for this
var (
idx int
name string
)
for idx, name = range names {
- if name == tunnelName {
+ if name == tunnel.Name {
break
}
}
tray.ContextMenu().Actions().Insert(trayTunnelActionsOffset+idx, tunnelAction)
+
+ state, err := tunnel.State()
+ if err != nil {
+ return
+ }
+ tray.SetTunnelState(tunnel, state, false)
}
func (tray *Tray) removeTunnelAction(tunnelName string) {
@@ -143,21 +184,28 @@ func (tray *Tray) removeTunnelAction(tunnelName string) {
delete(tray.tunnels, tunnelName)
}
-func (tray *Tray) SetTunnelState(tunnel *service.Tunnel, state service.TunnelState) {
- tray.SetTunnelStateWithNotification(tunnel, state, true)
+func (tray *Tray) onTunnelChange(tunnel *service.Tunnel, state service.TunnelState, err error) {
+ tray.mtw.Synchronize(func() {
+ tray.SetTunnelState(tunnel, state, err == nil)
+ if !tray.mtw.Visible() && err != nil {
+ tray.ShowError("WireGuard Tunnel Error", err.Error())
+ }
+ })
}
-func (tray *Tray) SetTunnelStateWithNotification(tunnel *service.Tunnel, state service.TunnelState, showNotifications bool) {
- if icon, err := tray.mtw.tunnelsPage.tunnelsView.imageProvider.IconWithOverlayForState(tray.icon, state); err == nil {
- tray.SetIcon(icon)
+func (tray *Tray) updateGlobalState() {
+ state, err := service.IPCClientGlobalState()
+ if err != nil {
+ return
}
- tunnelAction := tray.tunnels[tunnel.Name]
+ if icon, err := iconProvider.IconWithOverlayForState(state); err == nil {
+ tray.SetIcon(icon)
+ }
actions := tray.ContextMenu().Actions()
statusAction := actions.At(0)
activeCIDRsAction := actions.At(1)
- deactivateAction := actions.At(2)
setTunnelActionsEnabled := func(enabled bool) {
for i := 0; i < len(tray.tunnels); i++ {
@@ -170,16 +218,37 @@ func (tray *Tray) SetTunnelStateWithNotification(tunnel *service.Tunnel, state s
case service.TunnelStarting:
statusAction.SetText("Status: Activating")
setTunnelActionsEnabled(false)
-
tray.SetToolTip("WireGuard: Activating...")
case service.TunnelStarted:
+ activeCIDRsAction.SetVisible(err == nil)
statusAction.SetText("Status: Active")
setTunnelActionsEnabled(true)
+ tray.SetToolTip("WireGuard: Activated")
+
+ case service.TunnelStopping:
+ statusAction.SetText("Status: Deactivating")
+ setTunnelActionsEnabled(false)
+ tray.SetToolTip("WireGuard: Deactivating...")
+
+ case service.TunnelStopped:
+ activeCIDRsAction.SetVisible(false)
+ statusAction.SetText("Status: Inactive")
+ setTunnelActionsEnabled(true)
+ tray.SetToolTip("WireGuard: Deactivated")
+ }
+}
+func (tray *Tray) SetTunnelState(tunnel *service.Tunnel, state service.TunnelState, showNotifications bool) {
+ tunnelAction := tray.tunnels[tunnel.Name]
+
+ actions := tray.ContextMenu().Actions()
+ activeCIDRsAction := actions.At(1)
+
+ switch state {
+ case service.TunnelStarted:
+ activeCIDRsAction.SetText("")
config, err := tunnel.RuntimeConfig()
- activeCIDRsAction.SetVisible(err == nil)
- deactivateAction.SetVisible(err == nil)
if err == nil {
var sb strings.Builder
for i, addr := range config.Interface.Addresses {
@@ -189,46 +258,20 @@ func (tray *Tray) SetTunnelStateWithNotification(tunnel *service.Tunnel, state s
sb.WriteString(addr.String())
}
-
activeCIDRsAction.SetText(fmt.Sprintf("Networks: %s", sb.String()))
}
-
tunnelAction.SetEnabled(true)
tunnelAction.SetChecked(true)
-
- tray.SetToolTip("WireGuard: Activated")
if showNotifications {
tray.ShowInfo("WireGuard Activated", fmt.Sprintf("The %s tunnel has been activated.", tunnel.Name))
}
- case service.TunnelStopping:
- statusAction.SetText("Status: Deactivating")
- setTunnelActionsEnabled(false)
-
- tray.SetToolTip("WireGuard: Deactivating...")
-
case service.TunnelStopped:
- statusAction.SetText("Status: Inactive")
- activeCIDRsAction.SetVisible(false)
- deactivateAction.SetVisible(false)
- setTunnelActionsEnabled(true)
tunnelAction.SetChecked(false)
-
- tray.SetToolTip("WireGuard: Deactivated")
if showNotifications {
tray.ShowInfo("WireGuard Deactivated", fmt.Sprintf("The %s tunnel has been deactivated.", tunnel.Name))
}
}
-}
-func (tray *Tray) onActivateTunnel(tunnelName string) {
- if err := tray.mtw.TunnelTracker().ActivateTunnel(&service.Tunnel{tunnelName}); err != nil {
- walk.MsgBox(tray.mtw, "Failed to activate tunnel", err.Error(), walk.MsgBoxIconError)
- }
-}
-
-func (tray *Tray) onDeactivateTunnel() {
- if err := tray.mtw.TunnelTracker().DeactivateTunnel(); err != nil {
- walk.MsgBox(tray.mtw, "Failed to deactivate tunnel", err.Error(), walk.MsgBoxIconError)
- }
+ tray.updateGlobalState()
}