Giter VIP home page Giter VIP logo

systray's Introduction

Systray

systray is a cross-platform Go library to place an icon and menu in the notification area. This repository is a fork of getlantern/systray removing the GTK dependency and support for legacy linux system tray.

Features

  • Supported on Windows, macOS, Linux and many BSD systems
  • Menu items can be checked and/or disabled
  • Methods may be called from any Goroutine

API

package main

import "fyne.io/systray"
import "fyne.io/systray/example/icon"

func main() {
	systray.Run(onReady, onExit)
}

func onReady() {
	systray.SetIcon(icon.Data)
	systray.SetTitle("Awesome App")
	systray.SetTooltip("Pretty awesome超级棒")
	mQuit := systray.AddMenuItem("Quit", "Quit the whole app")

	// Sets the icon of a menu item.
	mQuit.SetIcon(icon.Data)
}

func onExit() {
	// clean up here
}

Running in a Fyne app

This repository is designed to allow any toolkit to integrate system tray without any additional dependencies. It is maintained by the Fyne team, but if you are using Fyne there is an even easier to use API in the main repository that wraps this project.

In your app you can use a standard fyne.Menu structure and pass it to SetSystemTrayMenu when your app is a desktop app, as follows:

	menu := fyne.NewMenu("MyApp",
		fyne.NewMenuItem("Show", func() {
			log.Println("Tapped show")
		}))

	if desk, ok := myApp.(desktop.App); ok {
		desk.SetSystemTrayMenu(menu)
	}

You can find out more in the toolkit documentation: System Tray Menu.

Run in another toolkit

Most graphical toolkits will grab the main loop so the Run code above is not possible. For this reason there is another entry point RunWithExternalLoop. This function of the library returns a start and end function that should be called when the application has started and will end, to loop in appropriate features.

See full API as well as CHANGELOG.

Note: this package requires cgo, so make sure you set CGO_ENABLED=1 before building.

Try the example app!

Have go v1.12+ or higher installed? Here's an example to get started on macOS or Linux:

git clone https://github.com/fyne-io/systray
cd systray/example
go run .

On Windows, you should follow the instructions above, but use the followign run command:

go run -ldflags "-H=windowsgui" .

Now look for Awesome App in your menu bar!

Awesome App screenshot

Platform notes

Linux/BSD

This implementation uses DBus to communicate through the SystemNotifier/AppIndicator spec, older tray implementations may not load the icon.

If you are running an older desktop environment, or system tray provider, you may require a proxy app which can convert the new DBus calls to the old format. The recommended tool for Gnome based trays is snixembed, others are available. Search for "StatusNotifierItems XEmbedded" in your package manager.

Windows

  • To avoid opening a console at application startup, use "fyne package" for your app or manually use these compile flags:
go build -ldflags -H=windowsgui

macOS

On macOS, you will need to create an application bundle to wrap the binary; simply use "fyne package" or add folders with the following minimal structure and assets:

SystrayApp.app/
  Contents/
    Info.plist
    MacOS/
      go-executable
    Resources/
      SystrayApp.icns

If bundling manually, you may want to add one or both of the following to your Info.plist:

	<!-- avoid having a blurry icon and text -->
	<key>NSHighResolutionCapable</key>
	<string>True</string>

	<!-- avoid showing the app on the Dock -->
	<key>LSUIElement</key>
	<string>1</string>

Consult the Official Apple Documentation here.

Credits

systray's People

Contributors

amkulikov avatar andydotxyz avatar atavism avatar bdwyertech avatar delthas avatar dhaavi avatar ersonp avatar essgeeeich avatar fffw avatar jacalz avatar jefvel avatar joesis avatar juja256 avatar kalikaneko avatar ksubileau avatar ldstein avatar leukipp avatar luckcolors avatar lucor avatar max-b avatar meskio avatar mrpalide avatar myleshorton avatar oxtoacart avatar romualdr avatar simonlindholm avatar slytomcat avatar stoggi avatar teddywing avatar tstromberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

systray's Issues

SetTitle not working in another module

Issue
The app has two calls to SetTitle. The first sets the title correctly to "Buggy". The second one, called from another module, should set it to "Working", but it doesn't.

Expected
The tray title should say "Working"

Actual
The tray title says "Buggy"

Code

// main.go
package main

import (
	"github.com/wilsonsilva/systray-set-title-issue/tray"
)

func main() {
	tray.InitializeAndRun()
	tray.SetTitle("Working")
}
// tray/tray.go
package tray

import (
	"fyne.io/systray"
	"fyne.io/systray/example/icon"
)

func InitializeAndRun() {
	systray.Run(onReady, func() {})
}

func SetTitle(title string) {
	systray.SetTitle(title)
}

func onReady() {
	systray.SetIcon(icon.Data)
	systray.SetTitle("Buggy")
}

Environment

// go.mod
module github.com/wilsonsilva/systray-set-title-issue

go 1.21.4

require (
	fyne.io/systray v1.10.0 // indirect
	github.com/godbus/dbus/v5 v5.0.4 // indirect
	github.com/tevino/abool v1.2.0 // indirect
	golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect
)
// go.sum
fyne.io/systray v1.10.0 h1:Yr1D9Lxeiw3+vSuZWPlaHC8BMjIHZXJKkek706AfYQk=
fyne.io/systray v1.10.0/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

MacbookPro M1 Max 16-inch, 2021
MacOS Sonoma 14.0 (23A344)

Panic when not setting TemplateIcon

I am getting the following crash when cross-compiling from Linux to Windows and not setting the Template Icon:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x7c0348]

goroutine 21 [running]:
fyne.io/systray.(*winTray).setTooltip(0xb61380, {0x945b8f, 0xc0000860b0})
        /home/coezbek/go/pkg/mod/fyne.io/[email protected]/systray_windows.go:260 +0xc8

My code (note the commented out SetTemplateIcon). Everything properly works when I set the TemplateIcon.

func onReady() {
	// systray.SetTemplateIcon(icon.Data, icon.Data)
	systray.SetTitle("Awesome App")
	systray.SetTooltip("Nephrolytix Sentinel")
	addQuitItem()
}

func main() {
	onExit := func() {
		fmt.Println("OnExit called")
	}

	systray.Run(onReady, onExit)
}

Cross Compilation

Does available cross compilation for systray?
When I trying to build for MacOS on Linux machine, by GOOS=darwin GOARCH=amd64 go build example/main.go I get this error:

# github.com/fyne-io/systray
./systray.go:72:2: undefined: setInternalLoop
./systray.go:75:2: undefined: nativeLoop
./systray.go:83:9: undefined: nativeStart
./systray.go:83:22: undefined: nativeEnd
./systray.go:111:2: undefined: registerSystray
./systray.go:116:14: undefined: quit
./systray.go:141:2: undefined: addSeparator
./systray.go:195:2: undefined: hideMenuItem
./systray.go:200:2: undefined: showMenuItem
./systray.go:225:2: undefined: addOrUpdateMenuItem
./systray.go:225:2: too many errors

But is OK for windows, by GOOS=windows GOARCH=amd64 go build example/main.go!

systray not functional within snap sandbox

Checklist

  • I have searched the issue tracker for open issues that relate to the same problem, before opening a new one.
  • This issue only relates to a single bug. I will open new issues for any other problems.

Describe the bug

I have a Go application that uses systray to implement a tray menu, which works as expected on GNOME and KDE. When packaged up as a snap, however, the snap sandbox prevents the menu to function properly. I'm wondering if this is something others have noticed or potentially found a solution for?

The problem occurs on GNOME, but does not on KDE, it can be reproduced by running the Fyne systray example.

How to reproduce

  1. Start with an Ubuntu 22.04 environment
  2. Set up snapcraft: https://snapcraft.io/docs/snapcraft-quickstart
  3. Clone this repo: https://github.com/peterzen/systray-example-snap
  4. Build the snap:
cd systray-example-snap
snapcraft --verbose
...
Created snap package example_0.1_amd64.snap                                    
  1. Install the snap in devmode:
sudo snap install --devmode --dangerous example_0.1_amd64.snap
  1. Run the app: example
  2. Observe the systray menu has been created and it's functional (menu items work as expected)
  3. Remove the snap:
sudo snap remove example
  1. Install the snap without --devmode:
sudo snap install  --dangerous example_0.1_amd64.snap
  1. Run app: example
  2. Observe the systray icon being visible, but the menu does not respond to clicks.
  3. See AppArmor DENIED messages in the log:
journalctl |grep dbus

(further log information can be obtained using the snappy-debug tool.)
12. Transfer the .snap file to a KDE system, install it without --devmode. Run the app, observe the systray menu being fully functional.

Log messages

= AppArmor =
Time: Nov  5 14:57:02
Log: apparmor="DENIED" operation="capable" profile="/snap/snapd/20290/usr/lib/snapd/snap-confine" pid=26423 comm="snap-confine" capability=12  capname="net_admin"
Capability: net_admin
Suggestions:
* adjust program to not require 'CAP_NET_ADMIN' (see 'man 7 capabilities')
* add one of 'bluetooth-control, firewall-control, netlink-audit, netlink-connector, network-control, qualcomm-ipc-router' to 'plugs'
* do nothing if using systemd utility (eg, timedatectl): https://forum.snapcraft.io/t/managing-time-date-and-timezone-in-ubuntu-core/408/44
* do nothing (https://launchpad.net/bugs/1465724)

= AppArmor =
Time: Nov  5 14:57:02
Log: apparmor="DENIED" operation="capable" profile="/snap/snapd/20290/usr/lib/snapd/snap-confine" pid=26423 comm="snap-confine" capability=38  capname="perfmon"
Capability: perfmon
Suggestions:
* adjust program to not require 'CAP_PERFMON' (see 'man 7 capabilities')
* do nothing if program otherwise works properly

= AppArmor =
Time: Nov  5 14:57:02
Log: apparmor="DENIED" operation="dbus_method_call"  bus="session" path="/StatusNotifierMenu" interface="org.freedesktop.DBus.Properties" member="GetAll" name=":1.29" mask="receive" pid=26423 label="snap.example.example" peer_pid=1317 peer_label="unconfined"
DBus access

= AppArmor =
Time: Nov  5 14:57:02
Log: apparmor="DENIED" operation="dbus_method_call"  bus="session" path="/StatusNotifierMenu" interface="com.canonical.dbusmenu" member="AboutToShow" name=":1.29" mask="receive" pid=26423 label="snap.example.example" peer_pid=1317 peer_label="unconfined"
DBus access
Suggestion:
* try adding 'unity7' to 'plugs'

= AppArmor =
Time: Nov  5 14:57:02
Log: apparmor="DENIED" operation="dbus_method_call"  bus="session" path="/StatusNotifierMenu" interface="com.canonical.dbusmenu" member="GetLayout" name=":1.29" mask="receive" pid=26423 label="snap.example.example" peer_pid=1317 peer_label="unconfined"
DBus access
Suggestion:
* try adding 'unity7' to 'plugs'

Example code

https://github.com/peterzen/systray-example-snap

Fyne version

fyne.io/systray v1.10.0

Go compiler version

1.21.3

Operating system and version

Ubuntu Linux 22.04, 20.04

Additional Information

From the logs it would appear that the Fyne systray lib tries to talk to the system/session dbus, but some of the AppArmor rules created by the sandbox do not allow it. (When the snap is installed with --devmode, the AppArmor rules do not apply, hence the app working correctly in that case.)

Other Snap applications with systray integration work correctly on both KDE and GNOME, that indicates that the problem is related to the way Fyne systray uses the dbus. See https://snapcraft.io/signal-desktop as an example.

Applications have same `Id` under Linux

The status notifier plugin on Linux (XFCE) allows you to rearrange tray icons.

When running the example app, it looks like the Id property ("1") is used in this list:
id-1

All fyne-io/systray applications use the same entry and therefore cannot be rearranged/hidden individually. This property is hardcoded here:

Value: "1",

Changing the code section above to,

"Id": {
	Value:    t.title,
	...
},

will use the application Title in the list:
id-title

I'm not sure if this modification violates some specifications or if the property is related to the one used in:

name := fmt.Sprintf("org.kde.StatusNotifierItem-%d-1", os.Getpid()) // register id 1 for this process

If not, I would suggest this as a bug fix.

Duplicate symbol building on macOS

Building with wailsv2 on mac (11) I get this error

/usr/local/go/pkg/tool/darwin_amd64/link: running clang failed: exit status 1
duplicate symbol '_OBJC_CLASS_$_AppDelegate' in:
    /var/folders/hn/kchz9fwn4vxbg42s6yb3d8082p9k3x/T/go-link-109134485/000003.o
    /var/folders/hn/kchz9fwn4vxbg42s6yb3d8082p9k3x/T/go-link-109134485/000026.o
duplicate symbol '_OBJC_METACLASS_$_AppDelegate' in:
    /var/folders/hn/kchz9fwn4vxbg42s6yb3d8082p9k3x/T/go-link-109134485/000003.o
    /var/folders/hn/kchz9fwn4vxbg42s6yb3d8082p9k3x/T/go-link-109134485/000026.o
ld: 2 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Anyone seen this before?
fwiw here are my build flags

INFO  Build command: go build -gcflags "all=-N -l" -tags dev,devtools -o bin/myapp-dev-darwin-amd64
OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES GO111MODULE=on TERMINAL_EMULATOR=JetBrains-JediTerm _INTELLIJ_FORCE_SET_GOROOT=/usr/local/go __CFBundleIdentifier=com.jetbrains.goland  XPC_FLAGS=0x0  GOROOT=/usr/local/go CGO_CFLAGS=-mmacosx-version-min=10.13 CGO_ENABLED=1 CGO_LDFLAGS=-framework UniformTypeIdentifiers -mmacosx-version-min=10.13 GOOS=darwin GOARCH=amd64)

Error connecting to DBUS when running as root

Opening this here as part of issues raised over at fyne-io/fyne in fyne-io/fyne#3120. It seems like we are getting a nil object because we can't connect to the DBUS interface and are thus crashing. We should add check and fail gracefully instead.

Stack trace from the issue above:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x70 pc=0x8cfb76]

goroutine 1 [running, locked to thread]:
github.com/godbus/dbus/v5.(*Conn).export(0xc0005f3860?, 0xc0005f3830?, {0xa138af?, 0x6?}, {0xa1b4de?, 0x10?}, 0xb?)
        /home/fizlast/go/pkg/mod/github.com/godbus/dbus/[email protected]/export.go:383 +0x36
github.com/godbus/dbus/v5.(*Conn).exportMethodTable(0x984a80?, 0xc0005f3a88?, {0xa138af?, 0x13?}, {0xa1b4de?, 0x1a?}, 0x30?)
        /home/fizlast/go/pkg/mod/github.com/godbus/dbus/[email protected]/export.go:367 +0x11b
github.com/godbus/dbus/v5.(*Conn).ExportSubtreeMethodTable(...)
        /home/fizlast/go/pkg/mod/github.com/godbus/dbus/[email protected]/export.go:346
fyne.io/systray/internal/generated/notifier.ExportStatusNotifierItem(0x0?, {0xa138af, 0x13}, {0xb0bb20?, 0x117bcd0})
        /home/fizlast/go/pkg/mod/fyne.io/[email protected]/internal/generated/notifier/status_notifier_item.go:192 +0x338
fyne.io/systray.nativeStart()
        /home/fizlast/go/pkg/mod/fyne.io/[email protected]/systray_unix.go:168 +0x69
fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).runGL(0xc0003e0620)
        /home/fizlast/go/pkg/mod/fyne.io/fyne/[email protected]/internal/driver/glfw/loop.go:117 +0xdb
fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).Run(0xc0000003c0?)
        /home/fizlast/go/pkg/mod/fyne.io/fyne/[email protected]/internal/driver/glfw/driver.go:164 +0x33
fyne.io/fyne/v2/internal/driver/glfw.(*window).ShowAndRun(0xc0000003c0)
        /home/fizlast/go/pkg/mod/fyne.io/fyne/[email protected]/internal/driver/glfw/window.go:230 +0x2c
main.main()
        /home/fizlast/projects/temp/main.go:26 +0x236

Linux XFCE submenu empty

Hey there!
We have an app that use systray, and now I want to submit this report as issue.
On Gnome works like a charm. But XFCE is unstable in submenu!, and KDE Plasma is really strange and useless on submenus.
You can see bellow screencasts:

Screen Cast

Ubuntu

OS: Ubuntu 22.04 (Minimal Installation)
Desktop: Gnome 42.0

ubuntu2204.mp4

Nitrux (Debianbased)

OS: Nitrux 2.1.1
Desktop: KDE Plasma 5.24.4

nitrux.mov

Manjaro (Archbased)

OS: Manjaro 21.2.6
Desktop: XFCE

manjaro.mov

SetIcon() failed to set IconPixmap prop on Debian/Xfce

Hi,

I need to update my app's systray icon based on the state of my application. But SetIcon() for updating the systray icon does not seem to work, it prints the following error message:

2023/05/10 23:32:47 systray error: failed to set IconPixmap prop: dbus.Store: type mismatch: slice: cannot convert a value of []systray.PX into []systray.PX

I've created a small project to reproduce the bug:
https://github.com/cvilsmeier/fyne-tray-test

Menu width not restored when making text narrower

Set the title of a menu to a longer character, then restore it. The width of the menu will not be restored.

image
image
image

minimal reproducible example:

package main

import (
	"fmt"
	"time"

	"fyne.io/systray"
	"fyne.io/systray/example/icon"
)

func main() {
	onExit := func() {
		now := time.Now()
		fmt.Println("Exit at", now.String())
	}

	systray.Run(onReady, onExit)
}

func addQuitItem() {
	mQuit := systray.AddMenuItem("Quit", "Quit the whole app")
	mQuit.Enable()
	go func() {
		<-mQuit.ClickedCh
		fmt.Println("Requesting quit")
		systray.Quit()
		fmt.Println("Finished quitting")
	}()
	systray.AddSeparator()
}

func onReady() {
	systray.SetTemplateIcon(icon.Data, icon.Data)
	systray.SetTitle("Awesome App")
	systray.SetTooltip("Lantern")
	addQuitItem()

	// We can manipulate the systray in other goroutines
	go func() {
		systray.SetTitle("Awesome App")
		systray.SetTooltip("Pretty awesome棒棒嗒")
		mChange := systray.AddMenuItem("Change Me", "Change Me")
		mRestore := systray.AddMenuItem("Restore Me", "Restore Me")

		systray.AddMenuItem("Ignored", "Ignored")

		for {
			select {
			case <-mChange.ClickedCh:
				mChange.SetTitle("I've Changed, hahahahahaha")
			case <-mRestore.ClickedCh:
				mChange.SetTitle("Change Me")
			}
		}
	}()
}

Return errors instead of using log.Printf in library code

At a couple of places, the current implementation does not return an error when something fails, but instead does something like the following (taken from systray_windows.go, MenuItem.SetIcon)

	if err != nil {
		log.Printf("systray error: unable to write icon data to temp file: %s\n", err)
		return
	}

However, we would like to handle the error in our own application (and not log it at all). One might even argue, that a library should not write any log messages at all, and only return errors to the main application.

Any chance of a PR changing this behavior getting accepted? After all, it would break backwards compatibility because the function signatures would change from e.g. SetIcon(iconBytes []byte) to SetIcon(iconBytes []byte) error

How to use RunWithExternalLoop

Hello,

I'm trying to understand how RunWithExternalLoop works. Calling Run works as expected, but I was trying to see if I can not block the main thread using RunWithExternalLoop, but nothing seems to happen. What am I missing here?

Running on:
macOS Montery 12.5
Apple M1 Pro

package main

import (
	"bytes"
	"image"
	"image/color"
	"image/png"
	"time"

	"fyne.io/systray"
)

func main() {
	onReady := func() {
		systray.SetIcon(blackBox())
		systray.SetTooltip("test")
	}

	// this works and blocks the main thread
	// systray.Run(onReady, func() {})

	// this does not not show anything in sys tray
	start, _ := systray.RunWithExternalLoop(onReady, func() {})
	start()

	// expect to see a black box in systray while sleeping
	time.Sleep(time.Second * 10)
}

func blackBox() []byte {
	// create an image
	img := image.NewRGBA(image.Rect(0, 0, 32, 32))

	// set all pixels to black
	for y := 0; y < 32; y++ {
		for x := 0; x < 32; x++ {
			img.Set(x, y, color.Black)
		}
	}

	// return image bytes
	buf := new(bytes.Buffer)
	png.Encode(buf, img)
	return buf.Bytes()
}

Thank you for your help!

Build menus on demand

Sometimes, a menu hierarchy is not known when the application starts, and it is expensive to fully populate the menu. It would be therefore be great if a menu could be built on demand (when hovered on a mac, or when clicked on a Linux).

Ideally, this would be implemented by providing a way to register a callback function that would be called when the menu is about to be displayed. This function would then populate the menu. Ideally, such a callback function would also be possible on the top menu, and get called when the tray icon is clicked.

No systray menu showing on Linux

I have a Go app which needs to run on Linux, Windows, macOS. Getlantern has been a bit flakey for me and I am looking for something better. WebView falls a little short too. But one thing at a time.

I've tried the fyne systray and it works for me on Windows and Mac but not on Linux. Using the example code, I get the Icon but nothing more. Linux is my main development environment. Then I compile it again on Windows and macOS. Not cross-compiled.

I've tested on Linux Mint 20.3 Cinnamon with go 1.18.1. I get the icon and nothing else. It also did the same nothing on Ubuntu 20.04 and nothing at all on Fedora 35. Seems fine on Windows 10 and macOS.

And yes. The getlantern version works fine on the same systems. Except when they release new bugs.

Nothing other than vanilla installs here. In the debug testing, I created clean VMs (VMware 16) using Mint 20.3 (Cinnamon) and Ubuntu 20.04. Nothing special was installed other than the recommended OS updates. The behaviour matched my Development PC's Mint 20.3.

On Fedora 35 I did not get an icon either. But I'm hoping it's part of the same issue.

Using only the example code... And go 1.18.1 on Mint 20.3 Cinnamon. Not a VM but an Intel PC. Also using VScode.

The icon shows up. Hovering over the icon says "Awesome App". Right-click the icon and a tall skinny blank rectangle sometimes pops up (.5" w x 2" h). No text.

Looking forward to getting this going so I can stop using getlantern.

Thanks

go.mod:

module fsystray

go 1.18

require fyne.io/systray v1.9.0

require (
	github.com/godbus/dbus/v5 v5.0.4 // indirect
	golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect
)

main.go:

package main

import (
	"fmt"
	"io/ioutil"
	"time"

	"fyne.io/systray"
	"fyne.io/systray/example/icon"
)

func main() {
	onExit := func() {
		now := time.Now()
		ioutil.WriteFile(fmt.Sprintf(`on_exit_%d.txt`, now.UnixNano()), []byte(now.String()), 0644)
	}

	systray.Run(onReady, onExit)
}

func onReady() {
	systray.SetTemplateIcon(icon.Data, icon.Data)
	systray.SetTitle("Awesome App")
	systray.SetTooltip("Lantern")
	mQuit := systray.AddMenuItem("Quit", "Quit the whole app")
	go func() {
		<-mQuit.ClickedCh
		fmt.Println("Requesting quit")
		systray.Quit()
		fmt.Println("Finished quitting")
	}()

	// We can manipulate the systray in other goroutines
	go func() {
		systray.SetTemplateIcon(icon.Data, icon.Data)
		systray.SetTitle("Awesome App")
		systray.SetTooltip("Pretty awesome棒棒嗒")
		mChange := systray.AddMenuItem("Change Me", "Change Me")
		mChecked := systray.AddMenuItemCheckbox("Checked", "Check Me", true)
		mEnabled := systray.AddMenuItem("Enabled", "Enabled")
		// Sets the icon of a menu item. Only available on Mac.
		mEnabled.SetTemplateIcon(icon.Data, icon.Data)

		systray.AddMenuItem("Ignored", "Ignored")

		subMenuTop := systray.AddMenuItem("SubMenuTop", "SubMenu Test (top)")
		subMenuMiddle := subMenuTop.AddSubMenuItem("SubMenuMiddle", "SubMenu Test (middle)")
		subMenuBottom := subMenuMiddle.AddSubMenuItemCheckbox("SubMenuBottom - Toggle Panic!", "SubMenu Test (bottom) - Hide/Show Panic!", false)
		subMenuBottom2 := subMenuMiddle.AddSubMenuItem("SubMenuBottom - Panic!", "SubMenu Test (bottom)")

		systray.AddSeparator()
		mToggle := systray.AddMenuItem("Toggle", "Toggle some menu items")
		shown := true
		toggle := func() {
			if shown {
				subMenuBottom.Check()
				subMenuBottom2.Hide()
				mEnabled.Hide()
				shown = false
			} else {
				subMenuBottom.Uncheck()
				subMenuBottom2.Show()
				mEnabled.Show()
				shown = true
			}
		}

		for {
			select {
			case <-mChange.ClickedCh:
				mChange.SetTitle("I've Changed")
			case <-mChecked.ClickedCh:
				if mChecked.Checked() {
					mChecked.Uncheck()
					mChecked.SetTitle("Unchecked")
				} else {
					mChecked.Check()
					mChecked.SetTitle("Checked")
				}
			case <-mEnabled.ClickedCh:
				mEnabled.SetTitle("Disabled")
				mEnabled.Disable()
			case <-subMenuBottom2.ClickedCh:
				panic("panic button pressed")
			case <-subMenuBottom.ClickedCh:
				toggle()
			case <-mToggle.ClickedCh:
				toggle()
			case <-mQuit.ClickedCh:
				systray.Quit()
				fmt.Println("Quit2 now...")
				return
			}
		}
	}()
}

Handle missing or restarted systray on linux more gracefully

In the current design, any app using this systray library needs to be started after the process that exposes org.kde.StatusNotifierWatcher. If the app owning that name is absent of restarts after initial setup, the systray display is broken for the duration of the process lifetime. It would be nice to detect this condition and gracefully reconnect. WDYT?

Panic in disabling MenuItem

I want switch from getlantern to your fork because of cgo free, but I get this panic:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x90 pc=0xa35ced]

goroutine 8 [running]:
github.com/godbus/dbus/v5.(*Conn).getSerial(...)
	/home/ubuntu/me_skywire/vendor/github.com/godbus/dbus/v5/conn.go:354
github.com/godbus/dbus/v5.(*Conn).sendMessageAndIfClosed(0x0, 0xc0001cd6b0, 0xbcf6cc)
	/home/ubuntu/me_skywire/vendor/github.com/godbus/dbus/v5/conn.go:475 +0x2d
github.com/godbus/dbus/v5.(*Conn).Emit(0xc0001cd650, {0xbdd1ce, 0x13}, {0xc00019a510, 0x7f1cef789bc0}, {0xc000069680, 0x2, 0x2})
	/home/ubuntu/me_skywire/vendor/github.com/godbus/dbus/v5/export.go:223 +0x4dd
fyne.io/systray/internal/generated/menu.Emit(0xc000162f80, {0x12b6e58, 0xc0001cd650})
	/home/ubuntu/me_skywire/vendor/fyne.io/systray/internal/generated/menu/dbus_menu.go:88 +0x111
fyne.io/systray.refresh(...)
	/home/ubuntu/me_skywire/vendor/fyne.io/systray/systray_menu_linux.go:203
fyne.io/systray.addOrUpdateMenuItem(0xc000162f80)
	/home/ubuntu/me_skywire/vendor/fyne.io/systray/systray_menu_linux.go:131 +0x35b
fyne.io/systray.(*MenuItem).update(0xc000162f80)
	/home/ubuntu/me_skywire/vendor/fyne.io/systray/systray.go:224 +0x7e
fyne.io/systray.(*MenuItem).Disable(...)

when trying to run this part of code:

mLink = systray.AddMenuItem("Open UI", "Open UI in browser")
mLink.Disable()

Actually it works fine on getlantern. :(

Windows 11 & RunWithExternalLoop doesn't show menu

Hello, I have systray integrated with gioui and they work together great on Mac. However, on Windows 11 the app icon is present in the tray but the menu items added are not showing up.

Works:

systray.Run(onReady,func() {})

Not working:

func main() {
	// systray.Run(onReady,func() {})
	start, end := systray.RunWithExternalLoop(onReady, func() {})
	start()
	app.Main()
	end()
	os.Exit(0)
}

Any suggestion on how to get this working?

Linux: checkbox item Uncheck doesn't work in submenu

When I try to programmatically deselect a checkbox menu item (call Uncheck), it doesn't work if the menu item is part of a submenu.

I wrote a minimal example reproducing the issue. Basically, I wanted to emulate radio button group behavior which means only one item can be selected at a time and I need to deselect the previous selection without any associated input event.

While it works correctly in the root menu, it breaks when I use the same logic for submenu items.
The clicked item gets selected but the state of the others in the group doesn't change.

Here's the demonstration (tested in KDE):
https://github.com/nohajc/systray-issue-minimal-example

Thanks for any help.

BTW, I also wanted to submit a PR adding support for actual radio buttons (which are part of the dbusmenu interface) but I got stuck because of this issue. D-Bus basically only lets you select the type of the "tick" icon. It doesn't enforce any particular behavior so multiselect is still possible unless you add your own logic. Now, I believe my logic is correct but I was very surprised to see it doesn't work consistently.

Does this thing compile on M1?

GOOS=darwin GOARCH=arm64 go build -a -tags netgo -ldflags

GO111MODULE="off"
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/davidrenne/Library/Caches/go-build"
GOENV="/Users/davidrenne/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/davidrenne/Atlona-Dev/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/davidrenne/Atlona-Dev"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.17.12"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/0_/nswys1md33gflzj54n8r415r0000gn/T/go-build4155332733=/tmp/go-build -gno-record-gcc-switches -fno-common"

And I get this stack trace when building:

# fyne.io/systray
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:71:2: undefined: setInternalLoop
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:74:2: undefined: nativeLoop
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:82:9: undefined: nativeStart
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:82:22: undefined: nativeEnd
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:110:2: undefined: registerSystray
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:115:2: undefined: resetMenu
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:120:14: undefined: quit
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:145:2: undefined: addSeparator
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:199:2: undefined: hideMenuItem
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:204:2: undefined: showMenuItem
/Users/davidrenne/Atlona-Dev/pkg/mod/fyne.io/[email protected]/systray.go:204:2: too many errors

It'd be nice if I have the same tray as amd64 on OSX. How can this be implemented for arm?

Crash on my Linux setup

Traceback:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x90 pc=0x8c5b8d]

goroutine 15 [running]:
github.com/godbus/dbus/v5.(*Conn).getSerial(...)
	/home/krik/go/pkg/mod/github.com/godbus/dbus/[email protected]/conn.go:369
github.com/godbus/dbus/v5.(*Conn).sendMessageAndIfClosed(0x0, 0xc000520810, 0xc000520870?)
	/home/krik/go/pkg/mod/github.com/godbus/dbus/[email protected]/conn.go:490 +0x2d
github.com/godbus/dbus/v5.(*Conn).Emit(0xc0005207e0?, {0xad5c4d, 0x13}, {0xc00040e3c0, 0x24}, {0xc0000781e0?, 0x2, 0x2})
	/home/krik/go/pkg/mod/github.com/godbus/dbus/[email protected]/export.go:245 +0x4d0
fyne.io/systray/internal/generated/menu.Emit(0xc00031a140?, {0xbeb0f0, 0xc0005207e0})
	/home/krik/go/pkg/mod/fyne.io/[email protected]/internal/generated/menu/dbus_menu.go:88 +0x111
fyne.io/systray.refresh(...)
	/home/krik/go/pkg/mod/fyne.io/[email protected]/systray_menu_linux.go:203
fyne.io/systray.addOrUpdateMenuItem(0xc00031a140)
	/home/krik/go/pkg/mod/fyne.io/[email protected]/systray_menu_linux.go:131 +0x35b
fyne.io/systray.(*MenuItem).update(0xc00031a140)
	/home/krik/go/pkg/mod/fyne.io/[email protected]/systray.go:224 +0x7e
fyne.io/systray.(*MenuItem).Disable(...)
	/home/krik/go/pkg/mod/fyne.io/[email protected]/systray.go:189
main.onReady()
	/home/krik/wrk/traceiq/esf/esf.go:109 +0x92
fyne.io/systray.Register.func2()
	/home/krik/go/pkg/mod/fyne.io/[email protected]/systray.go:98 +0x32
created by fyne.io/systray.Register
	/home/krik/go/pkg/mod/fyne.io/[email protected]/systray.go:96 +0xc5

'Signal: Bus Error' when running on MacOS

I've been trying to use this package to integrate with an application written in Wails. However, whenever I try to run it, it throws an error saying signal: bus error. I've tried taking the basic example from the repo, but even that seems to throw the same error. I have a feeling something is wrong with CGO in my case.

My System

MacOS version: Ventura 13.1
Go Version: 20.2 (I've tried 1.19 and 1.17 but same result)
CC env in Go: /usr/bin/clang (I tried the default as well but same result)
GCCGO env in GO: gccgo

The Code

package main

import (
	"fmt"
	"time"

	"fyne.io/systray"
	"fyne.io/systray/example/icon"
)

func main() {
	onExit := func() {
		now := time.Now()
		fmt.Println("Exit at", now.String())
	}

	systray.Run(onReady, onExit)
}

func addQuitItem() {
	mQuit := systray.AddMenuItem("Quit", "Quit the whole app")
	mQuit.Enable()
	go func() {
		<-mQuit.ClickedCh
		fmt.Println("Requesting quit")
		systray.Quit()
		fmt.Println("Finished quitting")
	}()
	systray.AddSeparator()
}

func onReady() {
	systray.SetTemplateIcon(icon.Data, icon.Data)
	systray.SetTitle("Awesome App")
	systray.SetTooltip("Lantern")
	addQuitItem()

	// We can manipulate the systray in other goroutines
	go func() {
		systray.SetTemplateIcon(icon.Data, icon.Data)
		systray.SetTitle("Awesome App")
		systray.SetTooltip("Pretty awesome棒棒嗒")
		mChange := systray.AddMenuItem("Change Me", "Change Me")
		mChecked := systray.AddMenuItemCheckbox("Checked", "Check Me", true)
		mEnabled := systray.AddMenuItem("Enabled", "Enabled")
		// Sets the icon of a menu item. Only available on Mac.
		mEnabled.SetTemplateIcon(icon.Data, icon.Data)

		systray.AddMenuItem("Ignored", "Ignored")

		subMenuTop := systray.AddMenuItem("SubMenuTop", "SubMenu Test (top)")
		subMenuMiddle := subMenuTop.AddSubMenuItem("SubMenuMiddle", "SubMenu Test (middle)")
		subMenuBottom := subMenuMiddle.AddSubMenuItemCheckbox("SubMenuBottom - Toggle Panic!", "SubMenu Test (bottom) - Hide/Show Panic!", false)
		// subMenuMiddle.AddSeparator()
		subMenuBottom2 := subMenuMiddle.AddSubMenuItem("SubMenuBottom - Panic!", "SubMenu Test (bottom)")

		systray.AddSeparator()
		mToggle := systray.AddMenuItem("Toggle", "Toggle some menu items")
		shown := true
		toggle := func() {
			if shown {
				subMenuBottom.Check()
				subMenuBottom2.Hide()
				mEnabled.Hide()
				shown = false
			} else {
				subMenuBottom.Uncheck()
				subMenuBottom2.Show()
				mEnabled.Show()
				shown = true
			}
		}
		mReset := systray.AddMenuItem("Reset", "Reset all items")

		for {
			select {
			case <-mChange.ClickedCh:
				mChange.SetTitle("I've Changed")
			case <-mChecked.ClickedCh:
				if mChecked.Checked() {
					mChecked.Uncheck()
					mChecked.SetTitle("Unchecked")
				} else {
					mChecked.Check()
					mChecked.SetTitle("Checked")
				}
			case <-mEnabled.ClickedCh:
				mEnabled.SetTitle("Disabled")
				mEnabled.Disable()
			case <-subMenuBottom2.ClickedCh:
				panic("panic button pressed")
			case <-subMenuBottom.ClickedCh:
				toggle()
			case <-mReset.ClickedCh:
				systray.ResetMenu()
				addQuitItem()
			case <-mToggle.ClickedCh:
				toggle()
			}
		}
	}()
}

Command

go run .

Expected Behaviour

You should see a new icon on the system tray.

Actual Behaviour

An error is returned: signal: bus error

Any idea why this occurs? I've tried the same program on a Windows 10 machine and it works fine.

Deleting Menu Items

I’m not well-versed enough in C/CGO to determine if hiding and nulling a menu or submenu item will trigger it for garbage collection.

If not, this is a feature request to be able to delete a menu/submenu item properly. Use case is multiple dynamic submenus with a background goroutine populating/pruning items.

Icon only shows on single extended monitor (macos)

I've done a bit of digging, and i'm not 100% sure what is happening here, but it's a bit of a showstopper for my usages of fyne in general.

I am on MacOS, using a m1 laptop. I use a dock that extends my displays across two monitors plus the built in laptop monitor. My built in laptop monitor is my primary monitor.

When starting up an app using fyne systray, the system tray icon only shows up on the "middle" monitor's app menu/system tray.
To be clear, it does not show up on the "primary" monitor as defined in my settings, and does not show up on the 3rd monitor, but does show up on one extended monitor that is in the "middle" in my layout. As seen here:

image

Even though I have it set for each monitor to also show the system tray, which works for all other apps.

And then lastly, if I disconnect the monitors and go mobile with the laptop, no systray icon shows up at all. To be clear, when not connected to external monitors anymore, the fyne systray icons for my app (or the example one in this repo) do not show up on my system tray. All other system tray icons for other apps work as expected.

This is my laptop tray, even when disconnected from all other monitors and app is still running (or even restarted, doesn't matter):
image

Re-plugging in my external monitors makes both my custom app icon and the example from this repo show up, on the external (extended) monitor without restarting the app, or restarting it. Both work.

Ideally the app icon would show on all monitors per the mac setings, but at the very least needs to show up on the laptop monitor when nothing else is plugged in. If there's any debugging I can do to provide help lmk!

compilation error for linux_386

I'm trying to cross compile a systray app using goreleaser via github workflows in ci. But it fails during compilation with the following error:
image

systray not working on i3wm

The systray example in the fyne docs isn't working for me on i3wm. I'm using Manjaro, I was previously using KDE Plasma before switching to i3, and I can confirm that the systray does work if I switch back to KDE.

When I run the app with go run ., I get the message:

2024/03/02 20:27:35 systray error: failed to register: The name is not activatable

I tried building the app and running with sudo, and I get the following:

2024/03/02 20:34:06 systray error: failed to register: The name org.kde.StatusNotifierWatcher was not provided by any .service files

Googling that message I ended up finding another issue in this repo (#64) but I'm not sure these issues are related.

For additional context, I'm using Polybar on version 3.7.1, and the tray works fine for other apps.

If there's anything I can do to provide additional info, or help in some other way, I'm happy to help.

`SetTitle` is not working

Hi, thanks for creating a fork of lantern's systray.

I tried the below code with systray library

package main

import (
	"fyne.io/systray"
	"fyne.io/systray/example/icon"
)

func main() {
	systray.Run(onReady, onExit)
}

func onReady() {
	systray.SetIcon(icon.Data)
	systray.SetTitle("Awesome App")
	systray.SetTooltip("Pretty awesome超级棒")
	mQuit := systray.AddMenuItem("Quit", "Quit the whole app")

	// Sets the icon of a menu item. Only available on Mac and Windows.
	mQuit.SetIcon(icon.Data)
}

func onExit() {
	// clean up here
}

But I couldn't see the title in system tray
systray_issue

So was this intentional? Or this is an issue? Thanks in advance!

System and package details

OS: Ubuntu 21.10
Desktop environment: Gnome 40.4.0
Package version: fyne.io/systray v1.10.0
Go version: 1.18

Cannot create systray menu without StatusNotifierWatcher

I run a window manager on Linux (specifically spectrwm). My systray is provided by Polybar, a separate program that creates a lightweight status bar for window managers. Whenever I try to set a systray menu, I get the following error:

2022/11/09 21:42:59 systray error: failed to register our icon with the notifier watcher (maybe no tray is running?): The name org.kde.StatusNotifierWatcher was not provided by any .service files

The systray is in fact running (I am looking right at it and it's full of other non-fyne icons), but org.kde.StatusNotifierWatcher does not appear in the output of a DBus ListNames call. The only related name I see is org.kde.StatusNotifierItem-611597-1 which seems to be coming from the fyne app itself as the PID 611597 corresponds to the running fyne app.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.