diff options
-rw-r--r-- | ui/confview.go | 315 | ||||
-rw-r--r-- | ui/syntax/confview.c | 177 | ||||
-rw-r--r-- | ui/syntax/confview.go | 155 | ||||
-rw-r--r-- | ui/syntax/confview.h | 20 | ||||
-rw-r--r-- | ui/tests/Makefile | 30 | ||||
-rw-r--r-- | ui/tests/confview.go | 70 | ||||
-rw-r--r-- | ui/ui.go | 2 |
7 files changed, 416 insertions, 353 deletions
diff --git a/ui/confview.go b/ui/confview.go new file mode 100644 index 00000000..18723a0b --- /dev/null +++ b/ui/confview.go @@ -0,0 +1,315 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package ui + +import ( + "fmt" + "github.com/lxn/walk" + "github.com/lxn/win" + "golang.org/x/sys/windows" + "golang.zx2c4.com/wireguard/windows/conf" + "reflect" + "strconv" + "strings" + "unsafe" +) + +type labelTextLine struct { + label *walk.TextLabel + text *walk.LineEdit +} + +type interfaceView struct { + publicKey *labelTextLine + listenPort *labelTextLine + mtu *labelTextLine + addresses *labelTextLine + dns *labelTextLine +} + +type peerView struct { + publicKey *labelTextLine + presharedKey *labelTextLine + allowedIPs *labelTextLine + endpoint *labelTextLine + persistentKeepalive *labelTextLine + latestHandshake *labelTextLine + transfer *labelTextLine +} + +type ConfView struct { + *walk.ScrollView + name *walk.GroupBox + interfaze *interfaceView + peers map[conf.Key]*peerView + spacer *walk.Spacer + + originalWndProc uintptr + creatingThread uint32 +} + +func (lt *labelTextLine) show(text string) { + s, e := lt.text.TextSelection() + lt.text.SetText(text) + lt.label.SetVisible(true) + lt.text.SetVisible(true) + lt.text.SetTextSelection(s, e) +} + +func (lt *labelTextLine) hide() { + lt.text.SetText("") + lt.label.SetVisible(false) + lt.text.SetVisible(false) +} + +func newLabelTextLine(fieldName string, parent walk.Container) *labelTextLine { + lt := new(labelTextLine) + lt.label, _ = walk.NewTextLabel(parent) + lt.label.SetText(fieldName + ":") + lt.label.SetTextAlignment(walk.AlignHFarVNear) + lt.label.SetVisible(false) + + lt.text, _ = walk.NewLineEdit(parent) + win.SetWindowLong(lt.text.Handle(), win.GWL_EXSTYLE, win.GetWindowLong(lt.text.Handle(), win.GWL_EXSTYLE)&^win.WS_EX_CLIENTEDGE) + lt.text.SetReadOnly(true) + lt.text.SetBackground(walk.NullBrush()) + lt.text.SetVisible(false) + lt.text.FocusedChanged().Attach(func() { + lt.text.SetTextSelection(0, 0) + }) + return lt +} + +func newInterfaceView(parent walk.Container) *interfaceView { + iv := &interfaceView{ + newLabelTextLine("Public key", parent), + newLabelTextLine("Listen port", parent), + newLabelTextLine("MTU", parent), + newLabelTextLine("Addresses", parent), + newLabelTextLine("DNS", parent), + } + 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), + } + layoutInGrid(pv, parent.Layout().(*walk.GridLayout)) + return pv +} + +func layoutInGrid(view interface{}, layout *walk.GridLayout) { + v := reflect.ValueOf(view).Elem() + for i := 0; i < v.NumField(); i++ { + lt := (*labelTextLine)(unsafe.Pointer(v.Field(i).Pointer())) + layout.SetRange(lt.label, walk.Rectangle{0, i, 1, 1}) + layout.SetRange(lt.text, walk.Rectangle{2, i, 1, 1}) + } +} + +func (iv *interfaceView) apply(c *conf.Interface) { + iv.publicKey.show(c.PrivateKey.Public().String()) + + if c.ListenPort > 0 { + iv.listenPort.show(strconv.Itoa(int(c.ListenPort))) + } else { + iv.listenPort.hide() + } + + if c.Mtu > 0 { + iv.mtu.show(strconv.Itoa(int(c.Mtu))) + } else { + iv.mtu.hide() + } + + if len(c.Addresses) > 0 { + addrStrings := make([]string, len(c.Addresses)) + for i, address := range c.Addresses { + addrStrings[i] = address.String() + } + iv.addresses.show(strings.Join(addrStrings[:], ", ")) + } else { + iv.addresses.hide() + } + + if len(c.Dns) > 0 { + addrStrings := make([]string, len(c.Dns)) + for i, address := range c.Dns { + addrStrings[i] = address.String() + } + iv.dns.show(strings.Join(addrStrings[:], ", ")) + } else { + iv.dns.hide() + } +} + +func (pv *peerView) apply(c *conf.Peer) { + pv.publicKey.show(c.PublicKey.String()) + + if !c.PresharedKey.IsZero() { + pv.presharedKey.show("enabled") + } else { + pv.presharedKey.hide() + } + + if len(c.AllowedIPs) > 0 { + addrStrings := make([]string, len(c.AllowedIPs)) + for i, address := range c.AllowedIPs { + addrStrings[i] = address.String() + } + pv.allowedIPs.show(strings.Join(addrStrings[:], ", ")) + } else { + pv.allowedIPs.hide() + } + + if !c.Endpoint.IsEmpty() { + pv.endpoint.show(c.Endpoint.String()) + } else { + pv.endpoint.hide() + } + + if c.PersistentKeepalive > 0 { + pv.persistentKeepalive.show(strconv.Itoa(int(c.PersistentKeepalive))) + } else { + pv.persistentKeepalive.hide() + } + + if !c.LastHandshakeTime.IsEmpty() { + pv.latestHandshake.show(c.LastHandshakeTime.String()) + } else { + pv.latestHandshake.hide() + } + + if c.RxBytes > 0 || c.TxBytes > 0 { + pv.transfer.show(fmt.Sprintf("%s received, %s sent", c.RxBytes.String(), c.TxBytes.String())) + } else { + pv.transfer.hide() + } +} + +func newPaddedGroupGrid(parent walk.Container) (group *walk.GroupBox, err error) { + group, err = walk.NewGroupBox(parent) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + group.Dispose() + } + }() + layout := walk.NewGridLayout() + layout.SetMargins(walk.Margins{10, 15, 10, 5}) + err = group.SetLayout(layout) + if err != nil { + return nil, err + } + spacer, err := walk.NewHSpacerFixed(group, 10) + if err != nil { + return nil, err + } + layout.SetRange(spacer, walk.Rectangle{1, 0, 1, 1}) + return group, nil +} + +func NewConfView(parent walk.Container) (*ConfView, error) { + cv := new(ConfView) + cv.ScrollView, _ = walk.NewScrollView(parent) + cv.SetLayout(walk.NewVBoxLayout()) + cv.name, _ = newPaddedGroupGrid(cv) + cv.interfaze = newInterfaceView(cv.name) + cv.peers = make(map[conf.Key]*peerView) + cv.spacer, _ = walk.NewVSpacer(cv) + cv.creatingThread = windows.GetCurrentThreadId() + win.SetWindowLongPtr(cv.Handle(), win.GWLP_USERDATA, uintptr(unsafe.Pointer(cv))) + cv.originalWndProc = win.SetWindowLongPtr(cv.Handle(), win.GWL_WNDPROC, crossThreadMessageHijack) + return cv, nil +} + +//TODO: choose actual good value for this +const crossThreadUpdate = win.WM_APP + 17 + +var crossThreadMessageHijack = windows.NewCallback(func(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr { + cv := (*ConfView)(unsafe.Pointer(win.GetWindowLongPtr(hwnd, win.GWLP_USERDATA))) + if msg == crossThreadUpdate { + cv.setConfiguration((*conf.Config)(unsafe.Pointer(wParam))) + return 0 + } + return win.CallWindowProc(cv.originalWndProc, hwnd, msg, wParam, lParam) +}) + +func (cv *ConfView) SetConfiguration(c *conf.Config) { + if cv.creatingThread == windows.GetCurrentThreadId() { + cv.setConfiguration(c) + } else { + cv.SendMessage(crossThreadUpdate, uintptr(unsafe.Pointer(c)), 0) + } +} + +func (cv *ConfView) setConfiguration(c *conf.Config) { + hasSuspended := false + suspend := func() { + if !hasSuspended { + cv.SetSuspended(true) + hasSuspended = true + } + } + defer func() { + if hasSuspended { + cv.SetSuspended(false) + cv.SendMessage(win.WM_SIZING, 0, 0) //TODO: FILTHY HACK! And doesn't work when items disappear. + } + }() + title := "Interface: " + c.Name + if cv.name.Title() != title { + cv.name.SetTitle(title) + } + cv.interfaze.apply(&c.Interface) + inverse := make(map[*peerView]bool, len(cv.peers)) + for _, pv := range cv.peers { + inverse[pv] = true + } + didAddPeer := false + for _, peer := range c.Peers { + if pv := cv.peers[peer.PublicKey]; pv != nil { + pv.apply(&peer) + inverse[pv] = false + } else { + didAddPeer = true + suspend() + group, _ := newPaddedGroupGrid(cv) + group.SetTitle("Peer") + pv := newPeerView(group) + pv.apply(&peer) + cv.peers[peer.PublicKey] = pv + } + } + for pv, remove := range inverse { + if !remove { + continue + } + k, e := conf.NewPrivateKeyFromString(pv.publicKey.text.Text()) + if e != nil { + continue + } + suspend() + delete(cv.peers, *k) + groupBox := pv.publicKey.label.Parent().AsContainerBase().Parent().(*walk.GroupBox) + groupBox.Parent().Children().Remove(groupBox) + groupBox.Dispose() + } + if didAddPeer { + cv.Children().Remove(cv.spacer) + cv.Children().Add(cv.spacer) + } +} diff --git a/ui/syntax/confview.c b/ui/syntax/confview.c deleted file mode 100644 index b7e6657b..00000000 --- a/ui/syntax/confview.c +++ /dev/null @@ -1,177 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. - */ - -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> -#include <string.h> -#include <assert.h> -#include <windows.h> -#include <richedit.h> -#include <richole.h> -#include <tom.h> - -#include "confview.h" -#include "highlighter.h" - -static WNDPROC parent_proc; - -static void set_rtf(HWND hWnd, const char *str) -{ - SETTEXTEX settextex = { - .flags = ST_DEFAULT, - .codepage = CP_ACP - }; - CHARRANGE orig_selection; - POINT original_scroll; - - SendMessage(hWnd, WM_SETREDRAW, FALSE, 0); - SendMessage(hWnd, EM_EXGETSEL, 0, (LPARAM)&orig_selection); - SendMessage(hWnd, EM_GETSCROLLPOS, 0, (LPARAM)&original_scroll); - SendMessage(hWnd, EM_HIDESELECTION, TRUE, 0); - SendMessage(hWnd, EM_SETTEXTEX, (WPARAM)&settextex, (LPARAM)str); - SendMessage(hWnd, EM_SETSCROLLPOS, 0, (LPARAM)&original_scroll); - SendMessage(hWnd, EM_EXSETSEL, 0, (LPARAM)&orig_selection); - SendMessage(hWnd, EM_HIDESELECTION, FALSE, 0); - SendMessage(hWnd, WM_SETREDRAW, TRUE, 0); - HideCaret(hWnd); - RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); -} - -static void context_menu(HWND hWnd, INT x, INT y) -{ - GETTEXTLENGTHEX gettextlengthex = { - .flags = GTL_DEFAULT, - .codepage = CP_ACP - }; - /* This disturbing hack grabs the system edit menu normally used for the EDIT control. */ - HMENU popup, menu = LoadMenuW(GetModuleHandleW(L"comctl32.dll"), MAKEINTRESOURCEW(1)); - CHARRANGE selection = { 0 }; - bool has_selection, can_selectall; - UINT cmd; - - if (!menu) - return; - - SendMessage(hWnd, EM_EXGETSEL, 0, (LPARAM)&selection); - has_selection = selection.cpMax - selection.cpMin; - can_selectall = selection.cpMin || (selection.cpMax < SendMessage(hWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gettextlengthex, 0)); - - popup = GetSubMenu(menu, 0); - EnableMenuItem(popup, WM_COPY, MF_BYCOMMAND | (has_selection ? MF_ENABLED : MF_GRAYED)); - EnableMenuItem(popup, EM_SETSEL, MF_BYCOMMAND | (can_selectall ? MF_ENABLED : MF_GRAYED)); - - /* Delete items that we don't handle. */ - for (int ctl = GetMenuItemCount(popup) - 1; ctl >= 0; --ctl) { - MENUITEMINFOW menu_item = { - .cbSize = sizeof(MENUITEMINFOW), - .fMask = MIIM_FTYPE | MIIM_ID - }; - if (!GetMenuItemInfoW(popup, ctl, MF_BYPOSITION, &menu_item)) - continue; - if (menu_item.fType & MFT_SEPARATOR) - continue; - switch (menu_item.wID) { - case WM_COPY: - case EM_SETSEL: - continue; - } - DeleteMenu(popup, ctl, MF_BYPOSITION); - } - /* Delete trailing and adjacent separators. */ - for (int ctl = GetMenuItemCount(popup) - 1, end = true; ctl >= 0; --ctl) { - MENUITEMINFOW menu_item = { - .cbSize = sizeof(MENUITEMINFOW), - .fMask = MIIM_FTYPE - }; - if (!GetMenuItemInfoW(popup, ctl, MF_BYPOSITION, &menu_item)) - continue; - if (!(menu_item.fType & MFT_SEPARATOR)) { - end = false; - continue; - } - if (!end && ctl) { - if (!GetMenuItemInfoW(popup, ctl - 1, MF_BYPOSITION, &menu_item)) - continue; - if (!(menu_item.fType & MFT_SEPARATOR)) - continue; - } - DeleteMenu(popup, ctl, MF_BYPOSITION); - } - - if (x == -1 && y == -1) { - RECT rect; - GetWindowRect(hWnd, &rect); - x = rect.left + (rect.right - rect.left) / 2; - y = rect.top + (rect.bottom - rect.top) / 2; - } - - if (GetFocus() != hWnd) - SetFocus(hWnd); - - cmd = TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, x, y, 0, hWnd, NULL); - if (cmd) - SendMessage(hWnd, cmd, 0, cmd == EM_SETSEL ? -1 : 0); - - DestroyMenu(menu); -} - -static LRESULT CALLBACK child_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) -{ - switch (Msg) { - case WM_CREATE: - HideCaret(hWnd); - break; - case WM_LBUTTONDOWN: - case WM_SETFOCUS: { - LRESULT ret = parent_proc(hWnd, Msg, wParam, lParam); - HideCaret(hWnd); - return ret; - } - case WM_SETCURSOR: - return 0; - case PV_NEWRTF: - set_rtf(hWnd, (const char *)wParam); - return 0; - case WM_CONTEXTMENU: - context_menu(hWnd, LOWORD(lParam), HIWORD(lParam)); - return 0; - } - return parent_proc(hWnd, Msg, wParam, lParam); -} - -static long has_loaded = 0; - -bool register_conf_view(void) -{ - WNDCLASSEXW class = { .cbSize = sizeof(WNDCLASSEXW) }; - WNDPROC pp; - HANDLE lib; - - if (InterlockedCompareExchange(&has_loaded, 1, 0) != 0) - return !!parent_proc; - - lib = LoadLibraryExW(L"msftedit.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - if (!lib) - return false; - - if (!GetClassInfoExW(NULL, L"RICHEDIT50W", &class)) - goto err; - pp = class.lpfnWndProc; - if (!pp) - goto err; - class.cbSize = sizeof(WNDCLASSEXW); - class.hInstance = GetModuleHandleW(NULL); - class.lpszClassName = L"WgConfView"; - class.lpfnWndProc = child_proc; - if (!RegisterClassExW(&class)) - goto err; - parent_proc = pp; - return true; - -err: - FreeLibrary(lib); - return false; -} diff --git a/ui/syntax/confview.go b/ui/syntax/confview.go deleted file mode 100644 index ef1c4530..00000000 --- a/ui/syntax/confview.go +++ /dev/null @@ -1,155 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. - */ - -package syntax - -import ( - "fmt" - "strconv" - "strings" - "unsafe" - - "github.com/lxn/walk" - "golang.zx2c4.com/wireguard/windows/conf" -) - -// #include "confview.h" -import "C" - -type ConfView struct { - walk.WidgetBase - lastRtf string -} - -func (cv *ConfView) LayoutFlags() walk.LayoutFlags { - return walk.GrowableHorz | walk.GrowableVert | walk.GreedyHorz | walk.GreedyVert -} - -func (cv *ConfView) MinSizeHint() walk.Size { - return walk.Size{20, 12} -} - -func (cv *ConfView) SizeHint() walk.Size { - return walk.Size{200, 100} -} - -func (cv *ConfView) SetConfiguration(conf *conf.Config) { - var output strings.Builder - - if conf == nil { - t := byte(0) - cv.SendMessage(C.PV_NEWRTF, uintptr(unsafe.Pointer(&t)), 0) - return - } - - escape := func(s string) string { - var o strings.Builder - for i := 0; i < len(s); i++ { - if s[i] > 127 || s[i] == '}' || s[i] == '{' || s[i] == '\\' { - o.WriteString(fmt.Sprintf("\\'%d", s[i])) - continue - } - o.WriteByte(s[i]) - } - return o.String() - } - field := func(key, value string) { - output.WriteString(fmt.Sprintf("{\\b %s:} %s\\par", escape(key), escape(value))) - } - - output.WriteString("{\\rtf1\\ansi\\fs20") - - field("Interface", conf.Name) - field("Public Key", conf.Interface.PrivateKey.Public().String()) - if conf.Interface.ListenPort > 0 { - field("Listen Port", strconv.Itoa(int(conf.Interface.ListenPort))) - } - - if conf.Interface.Mtu > 0 { - field("MTU", strconv.Itoa(int(conf.Interface.Mtu))) - } - - if len(conf.Interface.Addresses) > 0 { - addrStrings := make([]string, len(conf.Interface.Addresses)) - for i, address := range conf.Interface.Addresses { - addrStrings[i] = address.String() - } - field("Address", strings.Join(addrStrings[:], ", ")) - } - - if len(conf.Interface.Dns) > 0 { - addrStrings := make([]string, len(conf.Interface.Dns)) - for i, address := range conf.Interface.Dns { - addrStrings[i] = address.String() - } - field("DNS", strings.Join(addrStrings[:], ", ")) - } - - for _, peer := range conf.Peers { - output.WriteString("\\par") - field("Peer", peer.PublicKey.String()) - - if !peer.PresharedKey.IsZero() { - output.WriteString("{\\b Preshared Key:} {\\i enabled}\\par") - } - - if len(peer.AllowedIPs) > 0 { - addrStrings := make([]string, len(peer.AllowedIPs)) - for i, address := range peer.AllowedIPs { - addrStrings[i] = address.String() - } - field("Allowed IPs", strings.Join(addrStrings[:], ", ")) - } - - if !peer.Endpoint.IsEmpty() { - field("Endpoint", peer.Endpoint.String()) - } - - if peer.PersistentKeepalive > 0 { - field("Persistent Keepalive", strconv.Itoa(int(peer.PersistentKeepalive))) - } - - if !peer.LastHandshakeTime.IsEmpty() { - field("Latest Handshake", peer.LastHandshakeTime.String()) - } - - if peer.RxBytes > 0 || peer.TxBytes > 0 { - field("Transfer", fmt.Sprintf("%s received, %s sent", peer.RxBytes.String(), peer.TxBytes.String())) - } - } - - output.WriteString("}") - - text := output.String() - if text == cv.lastRtf { - return - } - cv.lastRtf = text - - t := C.CString(text) - cv.SendMessage(C.PV_NEWRTF, uintptr(unsafe.Pointer(t)), 0) - C.free(unsafe.Pointer(t)) -} - -func NewConfView(parent walk.Container) (*ConfView, error) { - C.register_conf_view() - cv := &ConfView{ - lastRtf: "", - } - err := walk.InitWidget( - cv, - parent, - "WgConfView", - C.CONFVIEW_STYLE, - C.CONFVIEW_EXTSTYLE, - ) - if err != nil { - return nil, err - } - - cv.GraphicsEffects().Add(walk.InteractionEffect) - cv.GraphicsEffects().Add(walk.FocusEffect) - return cv, nil -} diff --git a/ui/syntax/confview.h b/ui/syntax/confview.h deleted file mode 100644 index d415dfe8..00000000 --- a/ui/syntax/confview.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. - */ - -#ifndef CONFVIEW_H -#define CONFVIEW_H - -#include <stdbool.h> -#include <windows.h> -#include <richedit.h> - -#define CONFVIEW_STYLE (WS_CHILD | WS_CLIPSIBLINGS | ES_MULTILINE | WS_VISIBLE | WS_VSCROLL | ES_READONLY | WS_TABSTOP | ES_WANTRETURN | ES_NOOLEDRAGDROP) -#define CONFVIEW_EXTSTYLE (WS_EX_TRANSPARENT) - -#define PV_NEWRTF (WM_USER + 0x3200) - -extern bool register_conf_view(void); - -#endif diff --git a/ui/tests/Makefile b/ui/tests/Makefile new file mode 100644 index 00000000..c71af21d --- /dev/null +++ b/ui/tests/Makefile @@ -0,0 +1,30 @@ +export CFLAGS := -O3 -Wall -std=gnu11 +export CC := x86_64-w64-mingw32-gcc +WINDRES := x86_64-w64-mingw32-windres +export CGO_ENABLED := 1 +export GOOS := windows +export GOARCH := amd64 + +DEPLOYMENT_HOST ?= winvm +DEPLOYMENT_PATH ?= Desktop + +all: tests.exe + +resources.syso: ../../resources.rc ../../manifest.xml ../icon/icon.ico + $(WINDRES) -i $< -o $@ -O coff + +rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) +tests.exe: resources.syso $(call rwildcard,..,*.go *.c *.h) + go build -ldflags="-s -w" -v -o $@ + +deploy: tests.exe + -ssh $(DEPLOYMENT_HOST) -- 'taskkill /im tests.exe /f' + scp tests.exe $(DEPLOYMENT_HOST):$(DEPLOYMENT_PATH) + +run: tests.exe + wine tests.exe + +clean: + rm -rf resources.syso tests.exe + +.PHONY: deploy run clean all diff --git a/ui/tests/confview.go b/ui/tests/confview.go new file mode 100644 index 00000000..6907d83d --- /dev/null +++ b/ui/tests/confview.go @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package main + +import ( + "github.com/lxn/walk" + "golang.zx2c4.com/wireguard/windows/conf" + "golang.zx2c4.com/wireguard/windows/ui" + "log" + "runtime" +) + + +const demoConfig = `[Interface] +PrivateKey = 6KpcbNFK4tKBciKBT2Rj6Z/sHBqxdV+p+nuNA5AlWGI= +Address = 192.168.4.84/24 +DNS = 8.8.8.8, 8.8.4.4, 1.1.1.1, 1.0.0.1 + +[Peer] +PublicKey = JRI8Xc0zKP9kXk8qP84NdUQA04h6DLfFbwJn4g+/PFs= +Endpoint = demo.wireguard.com:12912 +AllowedIPs = 0.0.0.0/0 +` + +func main(){ + mw, _ := walk.NewMainWindowWithName("Test ConfView") + mw.SetSize(walk.Size{600, 800}) + mw.SetLayout(walk.NewVBoxLayout()) + cv, err := ui.NewConfView(mw) + if err != nil { + log.Fatal(err) + } + config, _ := conf.FromWgQuick(demoConfig, "demo") + peer := config.Peers[0] + config.Peers = make([]conf.Peer, 0) + + pb1, _ := walk.NewPushButton(mw) + pb1.SetText("Add and increment") + pb1.Clicked().Attach(func() { + config.Interface.ListenPort++ + config.Peers = append(config.Peers, peer) + k,_ := conf.NewPrivateKey() + config.Peers[len(config.Peers) - 1].PublicKey = *k + cv.SetConfiguration(config) + }) + pb2, _ := walk.NewPushButton(mw) + pb2.SetText("Remove first peer") + pb2.Clicked().Attach(func() { + if len(config.Peers) < 1 { + return + } + config.Interface.ListenPort-- + config.Peers = config.Peers[1:] + cv.SetConfiguration(config) + }) + pb3, _ := walk.NewPushButton(mw) + pb3.SetText("Toggle MTU") + pb3.Clicked().Attach(func() { + config.Interface.Mtu = (config.Interface.Mtu + 1) % 2 + cv.SetConfiguration(config) + }) + mw.SetVisible(true) + mw.Show() + mw.Activate() + mw.Run() + runtime.KeepAlive(cv) +}
\ No newline at end of file @@ -97,7 +97,7 @@ func RunUI() { se.SetText(demoConfig) } - cv, _ := syntax.NewConfView(mw) + cv, _ := NewConfView(mw) cv.SetVisible(false) cv.SetEnabled(false) |