Overview
WireGuird is a GTK-based GUI application written in Go that provides a graphical interface for managing WireGuard VPN tunnels on Linux. The application follows a modular architecture with clear separation between UI management, settings persistence, and WireGuard control.Project Structure
The codebase is organized into the following main packages:main
Application entry point and window initialization
gui
UI logic, event handling, and tunnel management
settings
Configuration persistence and user preferences
Directory Layout
Core Components
Application Entry Point (main.go)
The application starts inmain.go, which handles:
Logger Initialization
Sets up structured logging using zerolog with a colored console writer
main.go:21
Window Creation
ThecreateWindow() function (main.go:86-154) handles:
- Loading the Glade UI file from embedded resources
- Building the GTK interface using
gtk.Builder - Creating the system tray indicator
- Initializing the GUI components via
gui.Create() - Applying CSS styles to the window
main.go:87-94
System Tray Integration
ThecreateTray() function (main.go:44-84) creates a system tray indicator using go-appindicator:
main.go:60-65
GUI Package (gui/)
Thegui package contains the core application logic for managing the user interface and WireGuard tunnels.
Key Constants (gui/gui.go)
gui/gui.go:17-22
Global State (gui/gui.go)
The package maintains several global variables for UI components and WireGuard control:gui/gui.go:24-34
The
wgc variable is a WireGuard control client from golang.zx2c4.com/wireguard/wgctrl, which provides programmatic access to WireGuard interfaces and configuration.GUI Initialization (gui.Create)
TheCreate() function (gui/gui.go:36-104) is the main GUI initialization entry point:
gui/gui.go:36-53
- WireGuard Client Setup - Creates a
wgctrl.Clientto interact with WireGuard - Device Detection - Checks for active WireGuard devices and updates the UI accordingly
- Window Creation - Initializes editor and settings windows (hidden by default)
- Tunnel Management - Creates the
Tunnelsstruct and callsCreate() - Update Checker - Starts a background goroutine to check for updates every 24 hours
Tunnels Management (gui/tunnels.go)
TheTunnels struct is the heart of the application, managing tunnel state and UI interaction:
gui/tunnels.go:42-70
Tunnels.Create() - Main Setup Function
Tunnels.Create() - Main Setup Function
The
Create() method (gui/tunnels.go:72-877) is extensive and handles:- Tunnel Scanning - Reads
.conffiles from/etc/wireguard/ - Button Handlers - Add, delete, edit, zip tunnels
- Connection Toggle - Activate/deactivate tunnels using
wg-quick - Real-time Updates - Background ticker to update transfer statistics
- Settings Sync - Bi-directional binding between UI and settings
Key Operations
Scanning Tunnels (gui/tunnels.go:988-1105)
gui/tunnels.go:988-1003
gui/tunnels.go:196-329)
The button click handler uses wg-quick to manage tunnel state:
gui/tunnels.go:232-241
WireGuird uses
wg-quick as a subprocess rather than directly manipulating WireGuard interfaces. This ensures compatibility with existing tunnel configurations and leverages wg-quick’s DNS and routing management.GTK Widget Helpers (gui/get/gtk.go)
Theget package provides type-safe accessor functions for retrieving GTK widgets from the builder:
gui/get/gtk.go:11-23
Button, Label, Entry, ListBox, TextView, etc.
These helper functions are auto-generated using
go generate (see main.go:1). This ensures type safety when accessing widgets defined in the Glade file.Settings Package (settings/)
Thesettings package handles user preferences and persistence.
Settings Structure
settings/settings.go:14-19
Persistence
Settings are stored as JSON in./wireguird.settings:
settings/settings.go:44-56
Load() function reads the settings file and unmarshals the JSON:
settings/settings.go:59-80
GTK Integration
WireGuird uses thegotk3 bindings to interact with GTK 3. The UI layout is defined in wireguird.glade, which is an XML file created with Glade (a GTK UI designer).
UI Loading Flow
Signal Handling
GTK uses signals for event handling. WireGuird connects to signals using theConnect() method:
gui/tunnels.go:196
"clicked"- Button clicks"activate"- Menu item activation, row selection"changed"- Text entry or checkbox changes"destroy"- Window close events"key-press-event"- Keyboard shortcuts (e.g., F5 to refresh)
WireGuard Control
WireGuird uses two mechanisms to control WireGuard:1. wgctrl Library (Read Operations)
For reading WireGuard state, the application usesgolang.zx2c4.com/wireguard/wgctrl:
gui/gui.go:49-53
gui/tunnels.go:1129-1138
gui/tunnels.go:857-872
2. wg-quick Command (Write Operations)
For activating and deactivating tunnels, WireGuird shells out towg-quick:
gui/tunnels.go:232-241
gui/tunnels.go:286-295
Using
wg-quick ensures that DNS settings, routing rules, and pre/post scripts defined in the tunnel configuration are properly executed. This matches the behavior of the command-line WireGuard tools.Resource Embedding
WireGuird embeds static resources (UI files, icons) into the binary usingfileb0x.
Build-time Generation
Thego:generate directives in main.go:1-2 run code generators:
main.go:1-2
- GTK Helper Generator - Generates the
gui/get/gtk.gowidget accessor functions - fileb0x - Embeds files specified in
fileb0x.tomlintostatic/ab0x.go
Runtime Access
Embedded files are accessed through thestatic package:
main.go:87-90
Logging
WireGuird useszerolog for structured logging with different levels (debug, info, error).
Log Configuration
main.go:21-22
horizontal package provides a colored console writer for better readability.
Debug Mode
The debug level is controlled by theDebug setting:
settings/settings.go:35-39
User-Facing Logs
WireGuird also displays logs in the UI via thewlog() function (gui/tunnels.go:1140-1165):
gui/tunnels.go:1140-1165
Concurrency and Thread Safety
GTK is not thread-safe, so all UI updates must happen on the main GTK thread. WireGuird usesglib.IdleAdd() to schedule UI updates from background goroutines:
gui/tunnels.go:868-871
Background Tasks
WireGuird uses goroutines for:- Update Checker - Checks GitHub for new releases every 24 hours (
gui/gui.go:82-100) - Stats Updater - Updates transfer statistics every second (
gui/tunnels.go:833-874)
Error Handling
Errors are displayed to users via GTK message dialogs:gui/gui.go:106-118
Summary
WireGuird’s architecture demonstrates:- Clean separation of concerns between UI, business logic, and persistence
- Effective use of GTK bindings through gotk3 and Glade
- Hybrid WireGuard control using both the wgctrl library and wg-quick
- Proper GTK threading with
glib.IdleAdd()for UI updates - Resource embedding for single-binary distribution
- Structured logging with user-facing log display
