trayhost

package module
v0.0.0-...-e0155a1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2023 License: MIT Imports: 5 Imported by: 5

README

trayhost

Go Reference

Package trayhost is a cross-platform Go library to place an icon in the host operating system's taskbar.

Platform Support

  • macOS - Fully implemented and supported by @dmitshur.
  • Linux - Partially implemented, but unsupported (needs an owner/maintainer).
  • Windows - Partially implemented, but unsupported (needs an owner/maintainer).

Notes

On macOS, for Notification Center user notifications to work, your Go binary that uses trayhost must be a part of a standard macOS app bundle.

Most other functionality of trayhost will be available if the binary is not a part of app bundle, but you will get a terminal pop up, and you will not be able to configure some aspects of the app.

Here's a minimal layout of an app bundle:

$ tree "Trayhost Example.app"
Trayhost\ Example.app
└── Contents
    ├── Info.plist
    ├── MacOS
    │   └── example
    └── Resources
        └── Icon.icns

Here's a minimal Info.plist file as reference (only the entries that are needed, nothing extra):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>example</string>
	<key>CFBundleIconFile</key>
	<string>Icon</string>
	<key>CFBundleIdentifier</key>
	<string>ExampleApp</string>
	<key>NSHighResolutionCapable</key>
	<true/>
	<key>LSUIElement</key>
	<string>1</string>
</dict>
</plist>
  • CFBundleIdentifier needs to be set to some value for Notification Center to work.
  • The binary must be inside Contents/MacOS directory for Notification Center to work.
  • NSHighResolutionCapable to enable Retina mode.
  • LSUIElement is needed to make the app not appear in Cmd+Tab list and the dock while still being able to show a tooltip in the menu bar.

On macOS, when you run an app bundle, the working directory of the executed process is the root directory (/), not the app bundle's Contents/Resources directory. Change directory to Resources if you need to load resources from there.

ep, err := os.Executable()
if err != nil {
	log.Fatalln("os.Executable:", err)
}
err = os.Chdir(filepath.Join(filepath.Dir(ep), "..", "Resources"))
if err != nil {
	log.Fatalln("os.Chdir:", err)
}

Installation

go get github.com/shurcooL/trayhost

License

Documentation

Overview

Package trayhost is a cross-platform Go library to place an icon in the host operating system's taskbar.

Platform Support

- macOS - Fully implemented and supported by @dmitshur.

- Linux - Partially implemented, but unsupported (needs an owner/maintainer).

- Windows - Partially implemented, but unsupported (needs an owner/maintainer).

Notes

On macOS, for Notification Center user notifications to work, your Go binary that uses trayhost must be a part of a standard macOS app bundle.

Most other functionality of trayhost will be available if the binary is not a part of app bundle, but you will get a terminal pop up, and you will not be able to configure some aspects of the app.

Here's a minimal layout of an app bundle:

$ tree "Trayhost Example.app"
Trayhost\ Example.app
└── Contents
    ├── Info.plist
    ├── MacOS
    │   └── example
    └── Resources
        └── Icon.icns

Here's a minimal Info.plist file as reference (only the entries that are needed, nothing extra):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>example</string>
	<key>CFBundleIconFile</key>
	<string>Icon</string>
	<key>CFBundleIdentifier</key>
	<string>ExampleApp</string>
	<key>NSHighResolutionCapable</key>
	<true/>
	<key>LSUIElement</key>
	<string>1</string>
</dict>
</plist>

- CFBundleIdentifier needs to be set to some value for Notification Center to work.

- The binary must be inside Contents/MacOS directory for Notification Center to work.

- NSHighResolutionCapable to enable Retina mode.

- LSUIElement is needed to make the app not appear in Cmd+Tab list and the dock while still being able to show a tooltip in the menu bar.

On macOS, when you run an app bundle, the working directory of the executed process is the root directory (/), not the app bundle's Contents/Resources directory. Change directory to Resources if you need to load resources from there.

ep, err := os.Executable()
if err != nil {
	log.Fatalln("os.Executable:", err)
}
err = os.Chdir(filepath.Join(filepath.Dir(ep), "..", "Resources"))
if err != nil {
	log.Fatalln("os.Chdir:", err)
}
Example
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/shurcooL/trayhost"
)

func main() {
	menuItems := []trayhost.MenuItem{
		{
			Title: "Example Item",
			Handler: func() {
				fmt.Println("do stuff")
			},
		},
		{
			Title: "Get Clipboard Content",
			Handler: func() {
				cc, err := trayhost.GetClipboardContent()
				if err != nil {
					fmt.Printf("GetClipboardContent() error: %v\n", err)
					return
				}

				fmt.Printf("Text: %q\n", cc.Text)
				fmt.Printf("Image: %v len(%v)\n", cc.Image.Kind, len(cc.Image.Bytes))
				fmt.Printf("Files: len(%v) %v\n", len(cc.Files), cc.Files)
			},
		},
		{
			Title: "Set Clipboard Text",
			Handler: func() {
				const text = "this text gets copied"

				trayhost.SetClipboardText(text)
				fmt.Printf("Text %q got copied into your clipboard.\n", text)
			},
		},
		{
			// Displaying notifications requires a proper app bundle and won't work without one.
			// See https://godoc.org/github.com/shurcooL/trayhost#hdr-Notes.

			Title: "Display Notification",
			Handler: func() {
				notification := trayhost.Notification{
					Title:   "Example Notification",
					Body:    "Notification body text is here.",
					Timeout: 3 * time.Second,
					Handler: func() {
						fmt.Println("do stuff when notification is clicked")
					},
				}
				if cc, err := trayhost.GetClipboardContent(); err == nil && cc.Image.Kind != "" {
					// Use image from clipboard as notification image.
					notification.Image = cc.Image
				}
				notification.Display()
			},
		},
		trayhost.SeparatorMenuItem(),
		{
			Title:   "Quit",
			Handler: trayhost.Exit,
		},
	}

	// On macOS, when you run an app bundle, the working directory of the executed process
	// is the root directory (/), not the app bundle's Contents/Resources directory.
	// Change directory to Resources so that we can load resources from there.
	ep, err := os.Executable()
	if err != nil {
		log.Fatalln("os.Executable:", err)
	}
	err = os.Chdir(filepath.Join(filepath.Dir(ep), "..", "Resources"))
	if err != nil {
		log.Fatalln("os.Chdir:", err)
	}

	// Load tray icon.
	iconData, err := ioutil.ReadFile("icon@2x.png")
	if err != nil {
		log.Fatalln(err)
	}

	trayhost.Initialize("Example App", iconData, menuItems)

	trayhost.EnterLoop()
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func EnterLoop

func EnterLoop()

EnterLoop enters main loop.

func Exit

func Exit()

Exit exits the application. It can be called from a MenuItem handler.

func Initialize

func Initialize(title string, imageData []byte, items []MenuItem)

Initialize sets up the application properties. imageData is the icon image in PNG format.

func SetClipboardText

func SetClipboardText(text string)

SetClipboardText sets the system clipboard to the specified UTF-8 encoded string.

This function may only be called from the main thread.

func UpdateMenu

func UpdateMenu(newMenu []MenuItem)

UpdateMenu removes all current menu items, and adds new menu items.

Types

type ClipboardContent

type ClipboardContent struct {
	Text  string
	Image Image
	Files []string
}

ClipboardContent holds the contents of system clipboard.

func GetClipboardContent

func GetClipboardContent() (ClipboardContent, error)

GetClipboardContent returns the contents of the system clipboard, if it contains or is convertible to a UTF-8 encoded string, image, and/or files.

This function may only be called from the main thread.

type Image

type Image struct {
	Kind  ImageKind
	Bytes []byte
}

Image is an encoded image of certain kind.

type ImageKind

type ImageKind string

ImageKind is a file extension in lower case: "png", "jpg", "tiff", etc. Empty string means no image.

type MenuItem struct {
	// Title is the title of menu item.
	//
	// If empty, it acts as a separator. SeparatorMenuItem can be used
	// to create such separator menu items.
	Title string

	// Enabled can optionally control if this menu item is enabled or disabled.
	//
	// nil means always enabled.
	Enabled func() bool

	// Handler is triggered when the item is activated. nil means no handler.
	Handler func()
}

MenuItem is a menu item.

func SeparatorMenuItem

func SeparatorMenuItem() MenuItem

SeparatorMenuItem creates a separator MenuItem.

type Notification

type Notification struct {
	Title string // Title of user notification.
	Body  string // Body of user notification.
	Image Image  // Image shown in the content of user notification.

	// Timeout specifies time after which the notification is cleared.
	//
	// A Timeout of zero means no timeout.
	Timeout time.Duration

	// Activation (click) handler.
	//
	// nil means no handler.
	Handler func()
}

Notification represents a user notification.

func (Notification) Display

func (n Notification) Display()

Display displays the user notification.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL