From 61a567ac0166a0cf4af42d5bdff7438176223727 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Thu, 25 Jul 2019 15:12:04 +0200 Subject: ui: improve error handling Signed-off-by: Alexander Neumann --- ui/aboutdialog.go | 52 +++++++++-- ui/confview.go | 254 +++++++++++++++++++++++++++++++++++++++-------------- ui/editdialog.go | 84 +++++++++++++----- ui/filesave.go | 2 +- ui/logpage.go | 9 +- ui/managewindow.go | 12 ++- ui/raise.go | 3 +- ui/tray.go | 6 +- ui/tunnelspage.go | 67 +++++++++----- ui/ui.go | 22 ++++- ui/updatepage.go | 28 ++++-- 11 files changed, 401 insertions(+), 138 deletions(-) (limited to 'ui') diff --git a/ui/aboutdialog.go b/ui/aboutdialog.go index 8109b159..b56389bb 100644 --- a/ui/aboutdialog.go +++ b/ui/aboutdialog.go @@ -20,11 +20,22 @@ import ( var easterEggIndex = -1 func onAbout(owner walk.Form) { + showError(runAboutDialog(owner), owner) +} + +func runAboutDialog(owner walk.Form) error { vbl := walk.NewVBoxLayout() vbl.SetMargins(walk.Margins{80, 20, 80, 20}) vbl.SetSpacing(10) - dlg, _ := walk.NewDialogWithFixedSize(owner) + var disposables walk.Disposables + defer disposables.Treat() + + dlg, err := walk.NewDialogWithFixedSize(owner) + if err != nil { + return err + } + disposables.Add(dlg) dlg.SetTitle("About WireGuard") dlg.SetLayout(vbl) if icon, err := loadLogoIcon(32); err == nil { @@ -34,7 +45,10 @@ func onAbout(owner walk.Form) { font, _ := walk.NewFont("Segoe UI", 9, 0) dlg.SetFont(font) - iv, _ := walk.NewImageView(dlg) + iv, err := walk.NewImageView(dlg) + if err != nil { + return err + } iv.SetCursor(walk.CursorHand()) iv.MouseUp().Attach(func(x, y int, button walk.MouseButton) { if button == walk.LeftButton { @@ -55,34 +69,52 @@ func onAbout(owner walk.Form) { iv.SetImage(logo) } - wgLbl, _ := walk.NewTextLabel(dlg) + wgLbl, err := walk.NewTextLabel(dlg) + if err != nil { + return err + } wgFont, _ := walk.NewFont("Segoe UI", 16, walk.FontBold) wgLbl.SetFont(wgFont) wgLbl.SetTextAlignment(walk.AlignHCenterVNear) wgLbl.SetText("WireGuard") - detailsLbl, _ := walk.NewTextLabel(dlg) + detailsLbl, err := walk.NewTextLabel(dlg) + if err != nil { + return err + } detailsLbl.SetTextAlignment(walk.AlignHCenterVNear) detailsLbl.SetText(fmt.Sprintf("App version: %s\nGo backend version: %s\nGo version: %s\nOperating system: %s\nArchitecture: %s", version.RunningVersion(), device.WireGuardGoVersion, strings.TrimPrefix(runtime.Version(), "go"), version.OsName(), runtime.GOARCH)) - copyrightLbl, _ := walk.NewTextLabel(dlg) + copyrightLbl, err := walk.NewTextLabel(dlg) + if err != nil { + return err + } copyrightFont, _ := walk.NewFont("Segoe UI", 7, 0) copyrightLbl.SetFont(copyrightFont) copyrightLbl.SetTextAlignment(walk.AlignHCenterVNear) copyrightLbl.SetText("Copyright © 2015-2019 Jason A. Donenfeld. All Rights Reserved.") - buttonCP, _ := walk.NewComposite(dlg) + buttonCP, err := walk.NewComposite(dlg) + if err != nil { + return err + } hbl := walk.NewHBoxLayout() hbl.SetMargins(walk.Margins{VNear: 10}) buttonCP.SetLayout(hbl) walk.NewHSpacer(buttonCP) - closePB, _ := walk.NewPushButton(buttonCP) + closePB, err := walk.NewPushButton(buttonCP) + if err != nil { + return err + } closePB.SetAlignment(walk.AlignHCenterVNear) closePB.SetText("Close") closePB.Clicked().Attach(func() { dlg.Accept() }) - donatePB, _ := walk.NewPushButton(buttonCP) + donatePB, err := walk.NewPushButton(buttonCP) + if err != nil { + return err + } donatePB.SetAlignment(walk.AlignHCenterVNear) donatePB.SetText("♥ Donate!") donatePB.Clicked().Attach(func() { @@ -97,5 +129,9 @@ func onAbout(owner walk.Form) { dlg.SetDefaultButton(donatePB) dlg.SetCancelButton(closePB) + disposables.Spare() + dlg.Run() + + return nil } diff --git a/ui/confview.go b/ui/confview.go index 5a2e5dab..6d088fdc 100644 --- a/ui/confview.go +++ b/ui/confview.go @@ -98,25 +98,46 @@ func (lsl *labelStatusLine) update(state manager.TunnelState) { lsl.statusLabel.SetTextSelection(s, e) } -func newLabelStatusLine(parent walk.Container) *labelStatusLine { +func (lsl *labelStatusLine) Dispose() { + lsl.label.Dispose() + lsl.statusComposite.Dispose() +} + +func newLabelStatusLine(parent walk.Container) (*labelStatusLine, error) { + var err error + var disposables walk.Disposables + defer disposables.Treat() + lsl := new(labelStatusLine) - lsl.label, _ = walk.NewTextLabel(parent) + if lsl.label, err = walk.NewTextLabel(parent); err != nil { + return nil, err + } + disposables.Add(lsl.label) lsl.label.SetText("Status:") lsl.label.SetTextAlignment(walk.AlignHFarVNear) - lsl.statusComposite, _ = walk.NewComposite(parent) + if lsl.statusComposite, err = walk.NewComposite(parent); err != nil { + return nil, err + } + disposables.Add(lsl.statusComposite) layout := walk.NewHBoxLayout() layout.SetMargins(walk.Margins{}) layout.SetAlignment(walk.AlignHNearVNear) layout.SetSpacing(0) lsl.statusComposite.SetLayout(layout) - lsl.statusImage, _ = walk.NewImageView(lsl.statusComposite) + if lsl.statusImage, err = walk.NewImageView(lsl.statusComposite); err != nil { + return nil, err + } + disposables.Add(lsl.statusImage) lsl.statusImage.SetMargin(2) lsl.statusImage.SetMode(walk.ImageViewModeIdeal) - lsl.statusLabel, _ = walk.NewLineEdit(lsl.statusComposite) + if lsl.statusLabel, err = walk.NewLineEdit(lsl.statusComposite); err != nil { + return nil, err + } + disposables.Add(lsl.statusLabel) win.SetWindowLong(lsl.statusLabel.Handle(), win.GWL_EXSTYLE, win.GetWindowLong(lsl.statusLabel.Handle(), win.GWL_EXSTYLE)&^win.WS_EX_CLIENTEDGE) lsl.statusLabel.SetReadOnly(true) lsl.statusLabel.SetBackground(walk.NullBrush()) @@ -125,7 +146,9 @@ func newLabelStatusLine(parent walk.Container) *labelStatusLine { }) lsl.update(manager.TunnelUnknown) - return lsl + disposables.Spare() + + return lsl, nil } func (lt *labelTextLine) widgets() (walk.Widget, walk.Widget) { @@ -146,14 +169,30 @@ func (lt *labelTextLine) hide() { lt.text.SetVisible(false) } -func newLabelTextLine(fieldName string, parent walk.Container) *labelTextLine { +func (lt *labelTextLine) Dispose() { + lt.label.Dispose() + lt.text.Dispose() +} + +func newLabelTextLine(fieldName string, parent walk.Container) (*labelTextLine, error) { + var err error + var disposables walk.Disposables + defer disposables.Treat() + lt := new(labelTextLine) - lt.label, _ = walk.NewTextLabel(parent) + + if lt.label, err = walk.NewTextLabel(parent); err != nil { + return nil, err + } + disposables.Add(lt.label) lt.label.SetText(fieldName + ":") lt.label.SetTextAlignment(walk.AlignHFarVNear) lt.label.SetVisible(false) - lt.text, _ = walk.NewTextEdit(parent) + if lt.text, err = walk.NewTextEdit(parent); err != nil { + return nil, err + } + disposables.Add(lt.text) win.SetWindowLong(lt.text.Handle(), win.GWL_EXSTYLE, win.GetWindowLong(lt.text.Handle(), win.GWL_EXSTYLE)&^win.WS_EX_CLIENTEDGE) lt.text.SetCompactHeight(true) lt.text.SetReadOnly(true) @@ -162,7 +201,10 @@ func newLabelTextLine(fieldName string, parent walk.Container) *labelTextLine { lt.text.FocusedChanged().Attach(func() { lt.text.SetTextSelection(0, 0) }) - return lt + + disposables.Spare() + + return lt, nil } func (tal *toggleActiveLine) widgets() (walk.Widget, walk.Widget) { @@ -191,67 +233,121 @@ func (tal *toggleActiveLine) update(state manager.TunnelState) { tal.button.SetVisible(state != manager.TunnelUnknown) } -func newToggleActiveLine(parent walk.Container) *toggleActiveLine { +func (tal *toggleActiveLine) Dispose() { + tal.composite.Dispose() +} + +func newToggleActiveLine(parent walk.Container) (*toggleActiveLine, error) { + var err error + var disposables walk.Disposables + defer disposables.Treat() + tal := new(toggleActiveLine) - tal.composite, _ = walk.NewComposite(parent) + if tal.composite, err = walk.NewComposite(parent); err != nil { + return nil, err + } + disposables.Add(tal.composite) layout := walk.NewHBoxLayout() layout.SetMargins(walk.Margins{0, 0, 0, 6}) tal.composite.SetLayout(layout) - tal.button, _ = walk.NewPushButton(tal.composite) + if tal.button, err = walk.NewPushButton(tal.composite); err != nil { + return nil, err + } + disposables.Add(tal.button) walk.NewHSpacer(tal.composite) tal.update(manager.TunnelStopped) - return tal -} - -func newInterfaceView(parent walk.Container) *interfaceView { - iv := &interfaceView{ - newLabelStatusLine(parent), - newLabelTextLine("Public key", parent), - newLabelTextLine("Listen port", parent), - newLabelTextLine("MTU", parent), - newLabelTextLine("Addresses", parent), - newLabelTextLine("DNS servers", parent), - newToggleActiveLine(parent), - nil, - } - iv.lines = []widgetsLine{ - iv.status, - iv.publicKey, - iv.listenPort, - iv.mtu, - iv.addresses, - iv.dns, - iv.toggleActive, + disposables.Spare() + + return tal, nil +} + +type labelTextLineItem struct { + label string + ptr **labelTextLine +} + +func createLabelTextLines(items []labelTextLineItem, parent walk.Container, disposables *walk.Disposables) ([]widgetsLine, error) { + var err error + var disps walk.Disposables + defer disps.Treat() + + wls := make([]widgetsLine, len(items)) + for i, item := range items { + if *item.ptr, err = newLabelTextLine(item.label, parent); err != nil { + return nil, err + } + disps.Add(*item.ptr) + if disposables != nil { + disposables.Add(*item.ptr) + } + wls[i] = *item.ptr + } + + disps.Spare() + + return wls, nil +} + +func newInterfaceView(parent walk.Container) (*interfaceView, error) { + var err error + var disposables walk.Disposables + defer disposables.Treat() + + iv := new(interfaceView) + + if iv.status, err = newLabelStatusLine(parent); err != nil { + return nil, err + } + disposables.Add(iv.status) + + items := []labelTextLineItem{ + {"Public key", &iv.publicKey}, + {"Listen port", &iv.listenPort}, + {"MTU", &iv.mtu}, + {"Addresses", &iv.addresses}, + {"DNS servers", &iv.dns}, + } + if iv.lines, err = createLabelTextLines(items, parent, &disposables); err != nil { + return nil, err + } + + if iv.toggleActive, err = newToggleActiveLine(parent); err != nil { + return nil, err } + disposables.Add(iv.toggleActive) + + iv.lines = append([]widgetsLine{iv.status}, append(iv.lines, iv.toggleActive)...) + layoutInGrid(iv, parent.Layout().(*walk.GridLayout)) - return iv -} - -func newPeerView(parent walk.Container) *peerView { - pv := &peerView{ - newLabelTextLine("Public key", parent), - newLabelTextLine("Preshared key", parent), - newLabelTextLine("Allowed IPs", parent), - newLabelTextLine("Endpoint", parent), - newLabelTextLine("Persistent keepalive", parent), - newLabelTextLine("Latest handshake", parent), - newLabelTextLine("Transfer", parent), - nil, - } - pv.lines = []widgetsLine{ - pv.publicKey, - pv.presharedKey, - pv.allowedIPs, - pv.endpoint, - pv.persistentKeepalive, - pv.latestHandshake, - pv.transfer, + + disposables.Spare() + + return iv, nil +} + +func newPeerView(parent walk.Container) (*peerView, error) { + pv := new(peerView) + + items := []labelTextLineItem{ + {"Public key", &pv.publicKey}, + {"Preshared key", &pv.presharedKey}, + {"Allowed IPs", &pv.allowedIPs}, + {"Endpoint", &pv.endpoint}, + {"Persistent keepalive", &pv.persistentKeepalive}, + {"Latest handshake", &pv.latestHandshake}, + {"Transfer", &pv.transfer}, } + var err error + if pv.lines, err = createLabelTextLines(items, parent, nil); err != nil { + return nil, err + } + layoutInGrid(pv, parent.Layout().(*walk.GridLayout)) - return pv + + return pv, nil } func layoutInGrid(view widgetsLinesView, layout *walk.GridLayout) { @@ -381,18 +477,32 @@ func newPaddedGroupGrid(parent walk.Container) (group *walk.GroupBox, err error) } func NewConfView(parent walk.Container) (*ConfView, error) { + var err error + var disposables walk.Disposables + defer disposables.Treat() + cv := new(ConfView) - cv.ScrollView, _ = walk.NewScrollView(parent) + if cv.ScrollView, err = walk.NewScrollView(parent); err != nil { + return nil, err + } + disposables.Add(cv) vlayout := walk.NewVBoxLayout() vlayout.SetMargins(walk.Margins{5, 0, 5, 0}) cv.SetLayout(vlayout) - cv.name, _ = newPaddedGroupGrid(cv) - cv.interfaze = newInterfaceView(cv.name) + if cv.name, err = newPaddedGroupGrid(cv); err != nil { + return nil, err + } + if cv.interfaze, err = newInterfaceView(cv.name); err != nil { + return nil, err + } cv.interfaze.toggleActive.button.Clicked().Attach(cv.onToggleActiveClicked) cv.peers = make(map[conf.Key]*peerView) cv.tunnelChangedCB = manager.IPCClientRegisterTunnelChange(cv.onTunnelChanged) cv.SetTunnel(nil) - globalState, _ := manager.IPCClientGlobalState() + globalState, err := manager.IPCClientGlobalState() + if err != nil { + return nil, err + } cv.interfaze.toggleActive.updateGlobal(globalState) if err := walk.InitWrapperWindow(cv); err != nil { @@ -421,6 +531,9 @@ func NewConfView(parent walk.Container) (*ConfView, error) { } } }() + + disposables.Spare() + return cv, nil } @@ -443,11 +556,11 @@ func (cv *ConfView) onToggleActiveClicked() { if err != nil { cv.Synchronize(func() { if oldState == manager.TunnelUnknown { - walk.MsgBox(cv.Form(), "Failed to determine tunnel state", err.Error(), walk.MsgBoxIconError) + showErrorCustom(cv.Form(), "Failed to determine tunnel state", err.Error()) } else if oldState == manager.TunnelStopped { - walk.MsgBox(cv.Form(), "Failed to activate tunnel", err.Error(), walk.MsgBoxIconError) + showErrorCustom(cv.Form(), "Failed to activate tunnel", err.Error()) } else if oldState == manager.TunnelStarted { - walk.MsgBox(cv.Form(), "Failed to deactivate tunnel", err.Error(), walk.MsgBoxIconError) + showErrorCustom(cv.Form(), "Failed to deactivate tunnel", err.Error()) } }) } @@ -543,9 +656,16 @@ func (cv *ConfView) setTunnel(tunnel *manager.Tunnel, config *conf.Config, state pv.apply(&peer) inverse[pv] = false } else { - group, _ := newPaddedGroupGrid(cv) + group, err := newPaddedGroupGrid(cv) + if err != nil { + continue + } group.SetTitle("Peer") - pv := newPeerView(group) + pv, err := newPeerView(group) + if err != nil { + group.Dispose() + continue + } pv.apply(&peer) cv.peers[peer.PublicKey] = pv } diff --git a/ui/editdialog.go b/ui/editdialog.go index f27ab60f..8bcbbfeb 100644 --- a/ui/editdialog.go +++ b/ui/editdialog.go @@ -28,8 +28,25 @@ type EditDialog struct { blockUntunneledTraficCheckGuard bool } -func runTunnelEditDialog(owner walk.Form, tunnel *manager.Tunnel) *conf.Config { - dlg := &EditDialog{} +func runEditDialog(owner walk.Form, tunnel *manager.Tunnel) *conf.Config { + dlg, err := newEditDialog(owner, tunnel) + if showError(err, owner) { + return nil + } + + if dlg.Run() == walk.DlgCmdOK { + return &dlg.config + } + + return nil +} + +func newEditDialog(owner walk.Form, tunnel *manager.Tunnel) (*EditDialog, error) { + var err error + var disposables walk.Disposables + defer disposables.Treat() + + dlg := new(EditDialog) var title string if tunnel == nil { @@ -51,7 +68,10 @@ func runTunnelEditDialog(owner walk.Form, tunnel *manager.Tunnel) *conf.Config { layout.SetMargins(walk.Margins{10, 10, 10, 10}) layout.SetColumnStretchFactor(1, 3) - dlg.Dialog, _ = walk.NewDialog(owner) + if dlg.Dialog, err = walk.NewDialog(owner); err != nil { + return nil, err + } + disposables.Add(dlg) dlg.SetIcon(owner.Icon()) dlg.SetTitle(title) dlg.SetLayout(layout) @@ -60,34 +80,51 @@ func runTunnelEditDialog(owner walk.Form, tunnel *manager.Tunnel) *conf.Config { dlg.SetIcon(icon) } - nameLabel, _ := walk.NewTextLabel(dlg) + nameLabel, err := walk.NewTextLabel(dlg) + if err != nil { + return nil, err + } layout.SetRange(nameLabel, walk.Rectangle{0, 0, 1, 1}) nameLabel.SetTextAlignment(walk.AlignHFarVCenter) nameLabel.SetText("Name:") - dlg.nameEdit, _ = walk.NewLineEdit(dlg) + if dlg.nameEdit, err = walk.NewLineEdit(dlg); err != nil { + return nil, err + } layout.SetRange(dlg.nameEdit, walk.Rectangle{1, 0, 1, 1}) dlg.nameEdit.SetText(dlg.config.Name) - pubkeyLabel, _ := walk.NewTextLabel(dlg) + pubkeyLabel, err := walk.NewTextLabel(dlg) + if err != nil { + return nil, err + } layout.SetRange(pubkeyLabel, walk.Rectangle{0, 1, 1, 1}) pubkeyLabel.SetTextAlignment(walk.AlignHFarVCenter) pubkeyLabel.SetText("Public key:") - dlg.pubkeyEdit, _ = walk.NewLineEdit(dlg) + if dlg.pubkeyEdit, err = walk.NewLineEdit(dlg); err != nil { + return nil, err + } layout.SetRange(dlg.pubkeyEdit, walk.Rectangle{1, 1, 1, 1}) dlg.pubkeyEdit.SetReadOnly(true) dlg.pubkeyEdit.SetText("(unknown)") - dlg.syntaxEdit, _ = syntax.NewSyntaxEdit(dlg) + if dlg.syntaxEdit, err = syntax.NewSyntaxEdit(dlg); err != nil { + return nil, err + } layout.SetRange(dlg.syntaxEdit, walk.Rectangle{0, 2, 2, 1}) - buttonsContainer, _ := walk.NewComposite(dlg) + buttonsContainer, err := walk.NewComposite(dlg) + if err != nil { + return nil, err + } layout.SetRange(buttonsContainer, walk.Rectangle{0, 3, 2, 1}) buttonsContainer.SetLayout(walk.NewHBoxLayout()) buttonsContainer.Layout().SetMargins(walk.Margins{}) - dlg.blockUntunneledTrafficCB, _ = walk.NewCheckBox(buttonsContainer) + if dlg.blockUntunneledTrafficCB, err = walk.NewCheckBox(buttonsContainer); err != nil { + return nil, err + } dlg.blockUntunneledTrafficCB.SetText("Block untunneled traffic (kill-switch)") dlg.blockUntunneledTrafficCB.SetToolTipText("When a configuration has exactly one peer, and that peer has an allowed IPs containing at least one of 0.0.0.0/0 or ::/0, then the tunnel service engages a firewall ruleset to block all traffic that is neither to nor from the tunnel interface, with special exceptions for DHCP and NDP.") dlg.blockUntunneledTrafficCB.SetVisible(false) @@ -95,11 +132,16 @@ func runTunnelEditDialog(owner walk.Form, tunnel *manager.Tunnel) *conf.Config { walk.NewHSpacer(buttonsContainer) - dlg.saveButton, _ = walk.NewPushButton(buttonsContainer) + if dlg.saveButton, err = walk.NewPushButton(buttonsContainer); err != nil { + return nil, err + } dlg.saveButton.SetText("Save") dlg.saveButton.Clicked().Attach(dlg.onSaveButtonClicked) - cancelButton, _ := walk.NewPushButton(buttonsContainer) + cancelButton, err := walk.NewPushButton(buttonsContainer) + if err != nil { + return nil, err + } cancelButton.SetText("Cancel") cancelButton.Clicked().Attach(dlg.Cancel) @@ -118,11 +160,9 @@ func runTunnelEditDialog(owner walk.Form, tunnel *manager.Tunnel) *conf.Config { }) } - if dlg.Run() == walk.DlgCmdOK { - return &dlg.config - } + disposables.Spare() - return nil + return dlg, nil } func (dlg *EditDialog) onBlockUntunneledTrafficCBCheckedChanged() { @@ -217,7 +257,7 @@ func (dlg *EditDialog) onBlockUntunneledTrafficCBCheckedChanged() { return err: - walk.MsgBox(dlg, "Invalid configuration", "Unable to toggle untunneled traffic blocking state.", walk.MsgBoxIconWarning) + showErrorCustom(dlg, "Invalid configuration", "Unable to toggle untunneled traffic blocking state.") dlg.blockUntunneledTrafficCB.SetVisible(false) } @@ -252,11 +292,11 @@ func (dlg *EditDialog) onSyntaxEditPrivateKeyChanged(privateKey string) { func (dlg *EditDialog) onSaveButtonClicked() { newName := dlg.nameEdit.Text() if newName == "" { - walk.MsgBox(dlg, "Invalid name", "A name is required.", walk.MsgBoxIconWarning) + showWarningCustom(dlg, "Invalid name", "A name is required.") return } if !conf.TunnelNameIsValid(newName) { - walk.MsgBox(dlg, "Invalid name", fmt.Sprintf("Tunnel name ‘%s’ is invalid.", newName), walk.MsgBoxIconWarning) + showWarningCustom(dlg, "Invalid name", fmt.Sprintf("Tunnel name ‘%s’ is invalid.", newName)) return } newNameLower := strings.ToLower(newName) @@ -264,12 +304,12 @@ func (dlg *EditDialog) onSaveButtonClicked() { if newNameLower != strings.ToLower(dlg.config.Name) { existingTunnelList, err := manager.IPCClientTunnels() if err != nil { - walk.MsgBox(dlg, "Unable to list existing tunnels", err.Error(), walk.MsgBoxIconError) + showWarningCustom(dlg, "Unable to list existing tunnels", err.Error()) return } for _, tunnel := range existingTunnelList { if strings.ToLower(tunnel.Name) == newNameLower { - walk.MsgBox(dlg, "Tunnel already exists", fmt.Sprintf("Another tunnel already exists with the name ‘%s’.", newName), walk.MsgBoxIconWarning) + showWarningCustom(dlg, "Tunnel already exists", fmt.Sprintf("Another tunnel already exists with the name ‘%s’.", newName)) return } } @@ -277,7 +317,7 @@ func (dlg *EditDialog) onSaveButtonClicked() { cfg, err := conf.FromWgQuick(dlg.syntaxEdit.Text(), newName) if err != nil { - walk.MsgBox(dlg, "Unable to create new configuration", err.Error(), walk.MsgBoxIconError) + showErrorCustom(dlg, "Unable to create new configuration", err.Error()) return } diff --git a/ui/filesave.go b/ui/filesave.go index b17f106c..5f78cfee 100644 --- a/ui/filesave.go +++ b/ui/filesave.go @@ -18,7 +18,7 @@ func writeFileWithOverwriteHandling(owner walk.Form, filePath string, write func return false } - walk.MsgBox(owner, "Writing file failed", err.Error(), walk.MsgBoxIconError) + showErrorCustom(owner, "Writing file failed", err.Error()) return true } diff --git a/ui/logpage.go b/ui/logpage.go index 2eb27fa8..e4cfe603 100644 --- a/ui/logpage.go +++ b/ui/logpage.go @@ -24,11 +24,10 @@ const ( func NewLogPage() (*LogPage, error) { lp := &LogPage{} + var err error var disposables walk.Disposables defer disposables.Treat() - var err error - if lp.TabPage, err = walk.NewTabPage(); err != nil { return nil, err } @@ -47,7 +46,11 @@ func NewLogPage() (*LogPage, error) { lp.logView.SetAlternatingRowBGColor(walk.Color(win.GetSysColor(win.COLOR_BTNFACE))) lp.logView.SetLastColumnStretched(true) - contextMenu, _ := walk.NewMenu() + contextMenu, err := walk.NewMenu() + if err != nil { + return nil, err + } + lp.logView.AddDisposable(contextMenu) copyAction := walk.NewAction() copyAction.SetText("&Copy") copyAction.SetShortcut(walk.Shortcut{walk.ModControl, walk.KeyC}) diff --git a/ui/managewindow.go b/ui/managewindow.go index 7c643aba..60664abb 100644 --- a/ui/managewindow.go +++ b/ui/managewindow.go @@ -40,6 +40,8 @@ func init() { func NewManageTunnelsWindow() (*ManageTunnelsWindow, error) { var err error + var disposables walk.Disposables + defer disposables.Treat() font, err := walk.NewFont("Segoe UI", 9, 0) if err != nil { @@ -53,6 +55,7 @@ func NewManageTunnelsWindow() (*ManageTunnelsWindow, error) { if err != nil { return nil, err } + disposables.Add(mtw) win.ChangeWindowMessageFilterEx(mtw.Handle(), raiseMsg, win.MSGFLT_ALLOW, nil) mtw.SetPersistent(true) @@ -60,7 +63,6 @@ func NewManageTunnelsWindow() (*ManageTunnelsWindow, error) { mtw.SetIcon(icon) } mtw.SetTitle("WireGuard") - mtw.AddDisposable(font) mtw.SetFont(font) mtw.SetSize(walk.Size{670, 525}) mtw.SetMinMaxSize(walk.Size{500, 400}, walk.Size{0, 0}) @@ -85,7 +87,9 @@ func NewManageTunnelsWindow() (*ManageTunnelsWindow, error) { } }) - mtw.tabs, _ = walk.NewTabWidget(mtw) + if mtw.tabs, err = walk.NewTabWidget(mtw); err != nil { + return nil, err + } if mtw.tunnelsPage, err = NewTunnelsPage(); err != nil { return nil, err @@ -118,6 +122,8 @@ func NewManageTunnelsWindow() (*ManageTunnelsWindow, error) { }) } + disposables.Spare() + return mtw, nil } @@ -157,7 +163,7 @@ func (mtw *ManageTunnelsWindow) onTunnelChange(tunnel *manager.Tunnel, state man if len(errMsg) > 0 && errMsg[len(errMsg)-1] != '.' { errMsg += "." } - walk.MsgBox(mtw, "Tunnel Error", errMsg+"\n\nPlease consult the log for more information.", walk.MsgBoxIconWarning) + showWarningCustom(mtw, "Tunnel Error", errMsg+"\n\nPlease consult the log for more information.") } }) } diff --git a/ui/raise.go b/ui/raise.go index 6d08c6bb..b74b5ed6 100644 --- a/ui/raise.go +++ b/ui/raise.go @@ -10,7 +10,6 @@ import ( "os" "runtime" - "github.com/lxn/walk" "github.com/lxn/win" "golang.org/x/sys/windows" ) @@ -54,7 +53,7 @@ func WaitForRaiseUIThenQuit() { return 0 }, 0, 0, win.WINEVENT_SKIPOWNPROCESS|win.WINEVENT_OUTOFCONTEXT) if err != nil { - walk.MsgBox(nil, "WireGuard Detection Error", fmt.Sprintf("Unable to wait for WireGuard window to appear: %v", err), walk.MsgBoxIconError) + showErrorCustom(nil, "WireGuard Detection Error", fmt.Sprintf("Unable to wait for WireGuard window to appear: %v", err)) } for { var msg win.MSG diff --git a/ui/tray.go b/ui/tray.go index 26e06c4d..93b12c4c 100644 --- a/ui/tray.go +++ b/ui/tray.go @@ -160,11 +160,11 @@ func (tray *Tray) addTunnelAction(tunnel *manager.Tunnel) { tray.mtw.tunnelsPage.listView.selectTunnel(tclosure.Name) tray.mtw.tabs.SetCurrentIndex(0) if oldState == manager.TunnelUnknown { - walk.MsgBox(tray.mtw, "Failed to determine tunnel state", err.Error(), walk.MsgBoxIconError) + showErrorCustom(tray.mtw, "Failed to determine tunnel state", err.Error()) } else if oldState == manager.TunnelStopped { - walk.MsgBox(tray.mtw, "Failed to activate tunnel", err.Error(), walk.MsgBoxIconError) + showErrorCustom(tray.mtw, "Failed to activate tunnel", err.Error()) } else if oldState == manager.TunnelStarted { - walk.MsgBox(tray.mtw, "Failed to deactivate tunnel", err.Error(), walk.MsgBoxIconError) + showErrorCustom(tray.mtw, "Failed to deactivate tunnel", err.Error()) } }) } diff --git a/ui/tunnelspage.go b/ui/tunnelspage.go index 2eaad53d..09acec3d 100644 --- a/ui/tunnelspage.go +++ b/ui/tunnelspage.go @@ -36,7 +36,6 @@ type TunnelsPage struct { func NewTunnelsPage() (*TunnelsPage, error) { var err error - var disposables walk.Disposables defer disposables.Treat() @@ -55,18 +54,20 @@ func NewTunnelsPage() (*TunnelsPage, error) { vlayout.SetSpacing(0) tp.listContainer.SetLayout(vlayout) - // TODO: deal with remaining disposables in case the next line fails - if tp.listView, err = NewListView(tp.listContainer); err != nil { return nil, err } - tp.currentTunnelContainer, _ = walk.NewComposite(tp) + if tp.currentTunnelContainer, err = walk.NewComposite(tp); err != nil { + return nil, err + } vlayout = walk.NewVBoxLayout() vlayout.SetMargins(walk.Margins{}) tp.currentTunnelContainer.SetLayout(vlayout) - tp.fillerContainer, _ = walk.NewComposite(tp) + if tp.fillerContainer, err = walk.NewComposite(tp); err != nil { + return nil, err + } tp.fillerContainer.SetVisible(false) hlayout := walk.NewHBoxLayout() hlayout.SetMargins(walk.Margins{}) @@ -79,15 +80,23 @@ func NewTunnelsPage() (*TunnelsPage, error) { } }) - tp.confView, _ = NewConfView(tp.currentTunnelContainer) + if tp.confView, err = NewConfView(tp.currentTunnelContainer); err != nil { + return nil, err + } - controlsContainer, _ := walk.NewComposite(tp.currentTunnelContainer) + controlsContainer, err := walk.NewComposite(tp.currentTunnelContainer) + if err != nil { + return nil, err + } controlsContainer.SetLayout(walk.NewHBoxLayout()) controlsContainer.Layout().SetMargins(walk.Margins{}) walk.NewHSpacer(controlsContainer) - editTunnel, _ := walk.NewPushButton(controlsContainer) + editTunnel, err := walk.NewPushButton(controlsContainer) + if err != nil { + return nil, err + } editTunnel.SetEnabled(false) tp.listView.CurrentIndexChanged().Attach(func() { editTunnel.SetEnabled(tp.listView.CurrentIndex() > -1) @@ -107,22 +116,30 @@ func NewTunnelsPage() (*TunnelsPage, error) { return tp, nil } -func (tp *TunnelsPage) CreateToolbar() { +func (tp *TunnelsPage) CreateToolbar() error { if tp.listToolbar != nil { - return + return nil } // HACK: Because of https://github.com/lxn/walk/issues/481 // we need to put the ToolBar into its own Composite. - toolBarContainer, _ := walk.NewComposite(tp.listContainer) + toolBarContainer, err := walk.NewComposite(tp.listContainer) + if err != nil { + return err + } toolBarContainer.SetDoubleBuffering(true) hlayout := walk.NewHBoxLayout() hlayout.SetMargins(walk.Margins{}) toolBarContainer.SetLayout(hlayout) - tp.listToolbar, _ = walk.NewToolBarWithOrientationAndButtonStyle(toolBarContainer, walk.Horizontal, walk.ToolBarButtonImageBeforeText) + if tp.listToolbar, err = walk.NewToolBarWithOrientationAndButtonStyle(toolBarContainer, walk.Horizontal, walk.ToolBarButtonImageBeforeText); err != nil { + return err + } - addMenu, _ := walk.NewMenu() + addMenu, err := walk.NewMenu() + if err != nil { + return err + } tp.AddDisposable(addMenu) importAction := walk.NewAction() importAction.SetText("Import tunnel(s) from file...") @@ -172,7 +189,11 @@ func (tp *TunnelsPage) CreateToolbar() { fixContainerWidthToToolbarWidth() tp.listToolbar.SizeChanged().Attach(fixContainerWidthToToolbarWidth) - contextMenu, _ := walk.NewMenu() + contextMenu, err := walk.NewMenu() + if err != nil { + return err + } + tp.listView.AddDisposable(contextMenu) toggleAction := walk.NewAction() toggleAction.SetText("&Toggle") toggleAction.SetDefault(true) @@ -238,6 +259,8 @@ func (tp *TunnelsPage) CreateToolbar() { tp.listView.model.RowsRemoved().Attach(setExportRange) tp.listView.model.RowsReset().Attach(setExport) setExport() + + return nil } func (tp *TunnelsPage) updateConfView() { @@ -383,7 +406,7 @@ func (tp *TunnelsPage) exportTunnels(filePath string) { func (tp *TunnelsPage) addTunnel(config *conf.Config) { _, err := manager.IPCClientNewTunnel(config) if err != nil { - walk.MsgBox(tp.Form(), "Unable to create tunnel", err.Error(), walk.MsgBoxIconError) + showErrorCustom(tp.Form(), "Unable to create tunnel", err.Error()) } } @@ -400,11 +423,11 @@ func (tp *TunnelsPage) onTunnelsViewItemActivated() { if err != nil { tp.Synchronize(func() { if oldState == manager.TunnelUnknown { - walk.MsgBox(tp.Form(), "Failed to determine tunnel state", err.Error(), walk.MsgBoxIconError) + showErrorCustom(tp.Form(), "Failed to determine tunnel state", err.Error()) } else if oldState == manager.TunnelStopped { - walk.MsgBox(tp.Form(), "Failed to activate tunnel", err.Error(), walk.MsgBoxIconError) + showErrorCustom(tp.Form(), "Failed to activate tunnel", err.Error()) } else if oldState == manager.TunnelStarted { - walk.MsgBox(tp.Form(), "Failed to deactivate tunnel", err.Error(), walk.MsgBoxIconError) + showErrorCustom(tp.Form(), "Failed to deactivate tunnel", err.Error()) } }) return @@ -418,7 +441,7 @@ func (tp *TunnelsPage) onEditTunnel() { return } - if config := runTunnelEditDialog(tp.Form(), tunnel); config != nil { + if config := runEditDialog(tp.Form(), tunnel); config != nil { go func() { priorState, err := tunnel.State() tunnel.Delete() @@ -432,7 +455,7 @@ func (tp *TunnelsPage) onEditTunnel() { } func (tp *TunnelsPage) onAddTunnel() { - if config := runTunnelEditDialog(tp.Form(), nil); config != nil { + if config := runEditDialog(tp.Form(), nil); config != nil { // Save new tp.addTunnel(config) } @@ -493,9 +516,9 @@ func (tp *TunnelsPage) onDelete() { if len(errors) > 0 { tp.listView.Synchronize(func() { if len(errors) == 1 { - walk.MsgBox(tp.Form(), "Unable to delete tunnel", fmt.Sprintf("A tunnel was unable to be removed: %s", errors[0].Error()), walk.MsgBoxIconError) + showErrorCustom(tp.Form(), "Unable to delete tunnel", fmt.Sprintf("A tunnel was unable to be removed: %s", errors[0].Error())) } else { - walk.MsgBox(tp.Form(), "Unable to delete tunnels", fmt.Sprintf("%d tunnels were unable to be removed.", len(errors)), walk.MsgBoxIconError) + showErrorCustom(tp.Form(), "Unable to delete tunnels", fmt.Sprintf("%d tunnels were unable to be removed.", len(errors))) } }) } diff --git a/ui/ui.go b/ui/ui.go index aa0c7528..c98edf18 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -26,7 +26,7 @@ func RunUI() { runtime.LockOSThread() defer func() { if err := recover(); err != nil { - walk.MsgBox(nil, "Panic", fmt.Sprint(err, "\n\n", string(debug.Stack())), walk.MsgBoxIconError) + showErrorCustom(nil, "Panic", fmt.Sprint(err, "\n\n", string(debug.Stack()))) panic(err) } }() @@ -95,7 +95,7 @@ func RunUI() { if shouldQuitManagerWhenExiting { _, err := manager.IPCClientQuit(true) if err != nil { - walk.MsgBox(nil, "Error Exiting WireGuard", fmt.Sprintf("Unable to exit service due to: %v. You may want to stop WireGuard from the service manager.", err), walk.MsgBoxIconError) + showErrorCustom(nil, "Error Exiting WireGuard", fmt.Sprintf("Unable to exit service due to: %v. You may want to stop WireGuard from the service manager.", err)) } } } @@ -104,3 +104,21 @@ func onQuit() { shouldQuitManagerWhenExiting = true walk.App().Exit(0) } + +func showError(err error, owner walk.Form) bool { + if err == nil { + return false + } + + showErrorCustom(owner, "Error", err.Error()) + + return true +} + +func showErrorCustom(owner walk.Form, title, message string) { + walk.MsgBox(owner, title, message, walk.MsgBoxIconError) +} + +func showWarningCustom(owner walk.Form, title, message string) { + walk.MsgBox(owner, title, message, walk.MsgBoxIconWarning) +} diff --git a/ui/updatepage.go b/ui/updatepage.go index 95657798..9e73781f 100644 --- a/ui/updatepage.go +++ b/ui/updatepage.go @@ -19,12 +19,16 @@ type UpdatePage struct { } func NewUpdatePage() (*UpdatePage, error) { - up := &UpdatePage{} var err error + var disposables walk.Disposables + defer disposables.Treat() + + up := &UpdatePage{} if up.TabPage, err = walk.NewTabPage(); err != nil { return nil, err } + disposables.Add(up) up.SetTitle("An Update is Available!") @@ -33,18 +37,30 @@ func NewUpdatePage() (*UpdatePage, error) { up.SetLayout(walk.NewVBoxLayout()) - instructions, _ := walk.NewTextLabel(up) + instructions, err := walk.NewTextLabel(up) + if err != nil { + return nil, err + } instructions.SetText("An update to WireGuard is available. It is highly advisable to update without delay.") instructions.SetMinMaxSize(walk.Size{1, 0}, walk.Size{0, 0}) - status, _ := walk.NewTextLabel(up) + status, err := walk.NewTextLabel(up) + if err != nil { + return nil, err + } status.SetText("Status: Waiting for user") status.SetMinMaxSize(walk.Size{1, 0}, walk.Size{0, 0}) - bar, _ := walk.NewProgressBar(up) + bar, err := walk.NewProgressBar(up) + if err != nil { + return nil, err + } bar.SetVisible(false) - button, _ := walk.NewPushButton(up) + button, err := walk.NewPushButton(up) + if err != nil { + return nil, err + } updateIcon, _ := loadSystemIcon("shell32", 46, 32) button.SetImage(updateIcon) button.SetText("Update Now") @@ -113,5 +129,7 @@ func NewUpdatePage() (*UpdatePage, error) { }) }) + disposables.Spare() + return up, nil } -- cgit v1.2.3-59-g8ed1b