golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/ui/ui.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package ui
     7  
     8  import (
     9  	"fmt"
    10  	"runtime"
    11  	"runtime/debug"
    12  	"time"
    13  
    14  	"github.com/lxn/walk"
    15  	"github.com/lxn/win"
    16  	"golang.org/x/sys/windows"
    17  
    18  	"golang.zx2c4.com/wireguard/windows/l18n"
    19  	"golang.zx2c4.com/wireguard/windows/manager"
    20  	"golang.zx2c4.com/wireguard/windows/version"
    21  )
    22  
    23  var (
    24  	noTrayAvailable              = false
    25  	shouldQuitManagerWhenExiting = false
    26  	startTime                    = time.Now()
    27  	IsAdmin                      = false // A global, because this really is global for the process
    28  )
    29  
    30  func RunUI() {
    31  	runtime.LockOSThread()
    32  	windows.SetProcessPriorityBoost(windows.CurrentProcess(), false)
    33  	defer func() {
    34  		if err := recover(); err != nil {
    35  			showErrorCustom(nil, "Panic", fmt.Sprint(err, "\n\n", string(debug.Stack())))
    36  			panic(err)
    37  		}
    38  	}()
    39  
    40  	var (
    41  		err  error
    42  		mtw  *ManageTunnelsWindow
    43  		tray *Tray
    44  	)
    45  
    46  	for mtw == nil {
    47  		mtw, err = NewManageTunnelsWindow()
    48  		if err != nil {
    49  			time.Sleep(time.Millisecond * 400)
    50  		}
    51  	}
    52  
    53  	for tray == nil {
    54  		tray, err = NewTray(mtw)
    55  		if err != nil {
    56  			if version.OsIsCore() {
    57  				noTrayAvailable = true
    58  				break
    59  			}
    60  			time.Sleep(time.Millisecond * 400)
    61  		}
    62  	}
    63  
    64  	manager.IPCClientRegisterManagerStopping(func() {
    65  		mtw.Synchronize(func() {
    66  			walk.App().Exit(0)
    67  		})
    68  	})
    69  
    70  	onUpdateNotification := func(updateState manager.UpdateState) {
    71  		if updateState == manager.UpdateStateUnknown {
    72  			return
    73  		}
    74  		mtw.Synchronize(func() {
    75  			switch updateState {
    76  			case manager.UpdateStateFoundUpdate:
    77  				mtw.UpdateFound()
    78  				if tray != nil && IsAdmin {
    79  					tray.UpdateFound()
    80  				}
    81  			case manager.UpdateStateUpdatesDisabledUnofficialBuild:
    82  				mtw.SetTitle(l18n.Sprintf("%s (unsigned build, no updates)", mtw.Title()))
    83  			}
    84  		})
    85  	}
    86  	manager.IPCClientRegisterUpdateFound(onUpdateNotification)
    87  	go func() {
    88  		updateState, err := manager.IPCClientUpdateState()
    89  		if err == nil {
    90  			onUpdateNotification(updateState)
    91  		}
    92  	}()
    93  
    94  	if tray == nil {
    95  		win.ShowWindow(mtw.Handle(), win.SW_MINIMIZE)
    96  	}
    97  
    98  	mtw.Run()
    99  	if tray != nil {
   100  		tray.Dispose()
   101  	}
   102  	mtw.Dispose()
   103  
   104  	if shouldQuitManagerWhenExiting {
   105  		_, err := manager.IPCClientQuit(true)
   106  		if err != nil {
   107  			showErrorCustom(nil, l18n.Sprintf("Error Exiting WireGuard"), l18n.Sprintf("Unable to exit service due to: %v. You may want to stop WireGuard from the service manager.", err))
   108  		}
   109  	}
   110  }
   111  
   112  func onQuit() {
   113  	shouldQuitManagerWhenExiting = true
   114  	walk.App().Exit(0)
   115  }
   116  
   117  func showError(err error, owner walk.Form) bool {
   118  	if err == nil {
   119  		return false
   120  	}
   121  
   122  	showErrorCustom(owner, l18n.Sprintf("Error"), err.Error())
   123  
   124  	return true
   125  }
   126  
   127  func showErrorCustom(owner walk.Form, title, message string) {
   128  	walk.MsgBox(owner, title, message, walk.MsgBoxIconError)
   129  }
   130  
   131  func showWarningCustom(owner walk.Form, title, message string) {
   132  	walk.MsgBox(owner, title, message, walk.MsgBoxIconWarning)
   133  }