From d099b3eda13bda85a3763cb7a73543999c35e11f Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 26 Apr 2019 20:05:24 +0200 Subject: ui: simplify everything --- ui/tray.go | 173 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 108 insertions(+), 65 deletions(-) (limited to 'ui/tray.go') 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() } -- cgit v1.2.3-59-g8ed1b