WILT: Golang systray and fyne

Continuing to experiment with Golang and extend my capabilities in the compiled app space. I've played with making GUI to improve my efficiency at work with Sharepoint search and auto-pdf generators written in Fyne. Fyne being a very decent cross platform GUI framework for Golang. A colleague showed me a neat thing they'd written using systray - so you could make a wee menu icon to show status and pop up a menu. So I tried to combine the two.

This resulted in hours of frustration - both of them wanted to be the last thing in the Main window to terminate and run; especially Fyne. It took me a long time to find1 the systray's Register function that would wait until the main window was looping and then trigger. So now I've managed to get an app that runs into the systray and does not appear in the Windows taskbar. And when I click a menu item in the systray it pops up a full window that does appear in the taskbar and you can close it and not lose the app. Useful.

 1package main
 2
 3import (
 4	"fmt"
 5	"time"
 6
 7	"fyne.io/fyne/v2"
 8	app "fyne.io/fyne/v2/app"
 9	container "fyne.io/fyne/v2/container"
10	layout "fyne.io/fyne/v2/layout"
11	widget "fyne.io/fyne/v2/widget"
12	"github.com/getlantern/systray"
13	"github.com/skratchdot/open-golang/open"
14)
15
16var thisApp fyne.App
17var mainWindow fyne.Window
18var sabWindow fyne.Window
19
20func main() {
21	// Load Config
22	// Load Auth tokens
23    // Register systray's starting and exiting functions
24	systray.Register(onReady, onExit)
25	// Set up base GUI
26	thisApp = app.NewWithID("Test Application")
27	thisApp.SetIcon(resourceIconPng)
28	mainWindow = thisApp.NewWindow("Hidden Main Window")
29	mainWindow.Resize(fyne.NewSize(800, 800))
30	mainWindow.SetMaster()
31	mainWindow.Hide()
32	mainWindow.SetCloseIntercept(func() {
33		mainWindow.Hide()
34	})
35	sabWindow = thisApp.NewWindow("SAB Window")
36	sabWindow.Resize(fyne.NewSize(640, 480))
37	sabWindow.Hide()
38	sabWindow.SetCloseIntercept(func() {
39		sabWindow.Hide()
40	})
41	thisApp.Run()
42}
43
44func onReady() {
45	// Refresh any expired tokens
46	// Set up menu
47	systray.SetTemplateIcon(icon.Data, icon.Data)
48	title := "GU"
49	systray.SetTitle(title)
50	systray.SetTooltip(title)
51	mGSM := systray.AddMenuItem("SAB", "SAB")
52	systray.AddSeparator()
53	mAbout := systray.AddMenuItem("About", "About this app")
54	mPrefs := systray.AddMenuItem("Preferences", "Preferences")
55	mQuit := systray.AddMenuItem("Quit", "Quit this")
56	// Display Menu
57	go func() {
58		for {
59			select {
60			case <-mGSM.ClickedCh:
61				sabWindow.Show()
62			case <-mPrefs.ClickedCh:
63				open.Run("https://vonexplaino.com")
64			case <-mAbout.ClickedCh:
65				open.Run("https://vonexplaino.com/")
66			case <-mQuit.ClickedCh:
67				systray.Quit()
68				return
69			}
70		}
71	}()
72}

  1. It was in an example file where I finally found the register function. Thank heavens for people who write examples in their source code ↩︎