switch to fyne.io/systray

This commit is contained in:
nkanaev
2026-04-25 22:57:32 +01:00
parent f1bdbbc0af
commit 1bae41a350
74 changed files with 10196 additions and 846 deletions

13
vendor/fyne.io/systray/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,13 @@
example/example
webview_example/webview_example
*~
*.swp
**/*.exe
Release
Debug
*.sdf
dll/systray_unsigned.dll
out.txt
.vs
on_exit*.txt
.vscode

125
vendor/fyne.io/systray/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,125 @@
# Changelog
## [v1.1.0](https://github.com/getlantern/systray/tree/v1.1.0) (2020-11-18)
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.5...v1.1.0)
**Merged pull requests:**
- Add submenu support for Linux [\#183](https://github.com/getlantern/systray/pull/183) ([fbrinker](https://github.com/fbrinker))
- Add checkbox support for Linux [\#181](https://github.com/getlantern/systray/pull/181) ([fbrinker](https://github.com/fbrinker))
- fix SetTitle documentation [\#179](https://github.com/getlantern/systray/pull/179) ([delthas](https://github.com/delthas))
## [v1.0.5](https://github.com/getlantern/systray/tree/v1.0.5) (2020-10-19)
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.4...v1.0.5)
**Merged pull requests:**
- start menu ID with positive, and change the type to uint32 [\#173](https://github.com/getlantern/systray/pull/173) ([joesis](https://github.com/joesis))
- Allows disabling items in submenu on macOS [\#172](https://github.com/getlantern/systray/pull/172) ([joesis](https://github.com/joesis))
- Does not use the template icon for regular icons [\#171](https://github.com/getlantern/systray/pull/171) ([sithembiso](https://github.com/sithembiso))
## [v1.0.4](https://github.com/getlantern/systray/tree/v1.0.4) (2020-07-21)
[Full Changelog](https://github.com/getlantern/systray/compare/1.0.3...v1.0.4)
**Merged pull requests:**
- protect shared data structures with proper mutexes [\#162](https://github.com/getlantern/systray/pull/162) ([joesis](https://github.com/joesis))
## [1.0.3](https://github.com/getlantern/systray/tree/1.0.3) (2020-06-11)
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.3...1.0.3)
## [v1.0.3](https://github.com/getlantern/systray/tree/v1.0.3) (2020-06-11)
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.2...v1.0.3)
**Merged pull requests:**
- have a workaround to avoid crash on old macOS versions [\#153](https://github.com/getlantern/systray/pull/153) ([joesis](https://github.com/joesis))
- Fix bug on darwin of setting icon for menu [\#147](https://github.com/getlantern/systray/pull/147) ([mangalaman93](https://github.com/mangalaman93))
## [v1.0.2](https://github.com/getlantern/systray/tree/v1.0.2) (2020-05-19)
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.1...v1.0.2)
**Merged pull requests:**
- remove unused dependencies [\#145](https://github.com/getlantern/systray/pull/145) ([joesis](https://github.com/joesis))
## [v1.0.1](https://github.com/getlantern/systray/tree/v1.0.1) (2020-05-18)
[Full Changelog](https://github.com/getlantern/systray/compare/1.0.1...v1.0.1)
## [1.0.1](https://github.com/getlantern/systray/tree/1.0.1) (2020-05-18)
[Full Changelog](https://github.com/getlantern/systray/compare/1.0.0...1.0.1)
**Merged pull requests:**
- Unlock menuItemsLock before changing UI [\#144](https://github.com/getlantern/systray/pull/144) ([joesis](https://github.com/joesis))
## [1.0.0](https://github.com/getlantern/systray/tree/1.0.0) (2020-05-18)
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.0...1.0.0)
## [v1.0.0](https://github.com/getlantern/systray/tree/v1.0.0) (2020-05-18)
[Full Changelog](https://github.com/getlantern/systray/compare/0.9.0...v1.0.0)
**Merged pull requests:**
- Check if the menu item is nil [\#137](https://github.com/getlantern/systray/pull/137) ([myleshorton](https://github.com/myleshorton))
## [0.9.0](https://github.com/getlantern/systray/tree/0.9.0) (2020-03-24)
[Full Changelog](https://github.com/getlantern/systray/compare/v0.9.0...0.9.0)
## [v0.9.0](https://github.com/getlantern/systray/tree/v0.9.0) (2020-03-24)
[Full Changelog](https://github.com/getlantern/systray/compare/8e63b37ef27d94f6db79c4ffb941608e8f0dc2f9...v0.9.0)
**Merged pull requests:**
- Backport all features and fixes from master [\#140](https://github.com/getlantern/systray/pull/140) ([joesis](https://github.com/joesis))
- Nested menu windows [\#132](https://github.com/getlantern/systray/pull/132) ([joesis](https://github.com/joesis))
- Support for nested sub-menus on OS X [\#131](https://github.com/getlantern/systray/pull/131) ([oxtoacart](https://github.com/oxtoacart))
- Use temp directory for walk resource manager [\#129](https://github.com/getlantern/systray/pull/129) ([max-b](https://github.com/max-b))
- Added support for template icons on macOS [\#119](https://github.com/getlantern/systray/pull/119) ([oxtoacart](https://github.com/oxtoacart))
- When launching app window on macOS, make application a foreground app… [\#118](https://github.com/getlantern/systray/pull/118) ([oxtoacart](https://github.com/oxtoacart))
- Include stdlib.h in systray\_browser\_linux to explicitly declare funct… [\#114](https://github.com/getlantern/systray/pull/114) ([oxtoacart](https://github.com/oxtoacart))
- Fix panic when resources root path is not the working directory [\#112](https://github.com/getlantern/systray/pull/112) ([ksubileau](https://github.com/ksubileau))
- Don't print close reason to console [\#111](https://github.com/getlantern/systray/pull/111) ([ksubileau](https://github.com/ksubileau))
- Systray icon could not be changed dynamically [\#110](https://github.com/getlantern/systray/pull/110) ([ksubileau](https://github.com/ksubileau))
- Preventing deadlock on menu item ClickeCh when no one is listening, c… [\#105](https://github.com/getlantern/systray/pull/105) ([oxtoacart](https://github.com/oxtoacart))
- Reverted deadlock fix \(Affected other receivers\) [\#104](https://github.com/getlantern/systray/pull/104) ([ldstein](https://github.com/ldstein))
- Fix Deadlock and item ordering in Windows [\#103](https://github.com/getlantern/systray/pull/103) ([ldstein](https://github.com/ldstein))
- Minor README improvements \(go modules, example app, screenshot\) [\#98](https://github.com/getlantern/systray/pull/98) ([tstromberg](https://github.com/tstromberg))
- Add support for app window [\#97](https://github.com/getlantern/systray/pull/97) ([oxtoacart](https://github.com/oxtoacart))
- systray\_darwin.m: Compare Mac OS min version with value instead of macro [\#94](https://github.com/getlantern/systray/pull/94) ([teddywing](https://github.com/teddywing))
- Attempt to fix https://github.com/getlantern/systray/issues/75 [\#92](https://github.com/getlantern/systray/pull/92) ([mikeschinkel](https://github.com/mikeschinkel))
- Fix application path for MacOS in README [\#91](https://github.com/getlantern/systray/pull/91) ([zereraz](https://github.com/zereraz))
- Document cross-platform console window details [\#81](https://github.com/getlantern/systray/pull/81) ([michaelsanford](https://github.com/michaelsanford))
- Fix bad-looking system tray icon in Windows [\#78](https://github.com/getlantern/systray/pull/78) ([juja256](https://github.com/juja256))
- Add the separator to the visible items [\#76](https://github.com/getlantern/systray/pull/76) ([meskio](https://github.com/meskio))
- keep track of hidden items [\#74](https://github.com/getlantern/systray/pull/74) ([kalikaneko](https://github.com/kalikaneko))
- Support macOS older than 10.13 [\#73](https://github.com/getlantern/systray/pull/73) ([swznd](https://github.com/swznd))
- define ERROR\_SUCCESS as syscall.Errno [\#69](https://github.com/getlantern/systray/pull/69) ([joesis](https://github.com/joesis))
- Bug/fix broken menuitem show [\#68](https://github.com/getlantern/systray/pull/68) ([kalikaneko](https://github.com/kalikaneko))
- Fix mac deprecations [\#66](https://github.com/getlantern/systray/pull/66) ([jefvel](https://github.com/jefvel))
- Made it possible to add icons to menu items on Mac [\#65](https://github.com/getlantern/systray/pull/65) ([jefvel](https://github.com/jefvel))
- linux: delete temp files as soon as they are not needed [\#63](https://github.com/getlantern/systray/pull/63) ([meskio](https://github.com/meskio))
- Merge changes from amkulikov to remove DLL for windows [\#56](https://github.com/getlantern/systray/pull/56) ([oxtoacart](https://github.com/oxtoacart))
- Revert "Use templated icons for the menu bar in macOS" [\#51](https://github.com/getlantern/systray/pull/51) ([stoggi](https://github.com/stoggi))
- Use templated icons for the menu bar in macOS [\#46](https://github.com/getlantern/systray/pull/46) ([stoggi](https://github.com/stoggi))
- Syscalls instead of custom DLLs [\#44](https://github.com/getlantern/systray/pull/44) ([amkulikov](https://github.com/amkulikov))
- On quit exit main loop on linux [\#41](https://github.com/getlantern/systray/pull/41) ([meskio](https://github.com/meskio))
- Fixed hide show in linux \(\#37\) [\#39](https://github.com/getlantern/systray/pull/39) ([meskio](https://github.com/meskio))
- fix: linux compilation warning [\#36](https://github.com/getlantern/systray/pull/36) ([novln](https://github.com/novln))
- Added separator functionality [\#32](https://github.com/getlantern/systray/pull/32) ([oxtoacart](https://github.com/oxtoacart))
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*

202
vendor/fyne.io/systray/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2014 Brave New Software Project, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

18
vendor/fyne.io/systray/Makefile generated vendored Normal file
View File

@@ -0,0 +1,18 @@
tag-changelog: require-version require-gh-token
echo "Tagging..." && \
git tag -a "$$VERSION" -f --annotate -m"Tagged $$VERSION" && \
git push --tags -f && \
git checkout master && \
git pull && \
github_changelog_generator --no-issues --max-issues 100 --token "${GH_TOKEN}" --user getlantern --project systray && \
git add CHANGELOG.md && \
git commit -m "Updated changelog for $$VERSION" && \
git push origin HEAD && \
git checkout -
guard-%:
@ if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fi
require-version: guard-VERSION
require-gh-token: guard-GH_TOKEN

147
vendor/fyne.io/systray/README.md generated vendored Normal file
View File

@@ -0,0 +1,147 @@
# 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](https://github.com/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
```go
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:
```go
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](https://developer.fyne.io/explore/systray).
### 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](https://pkg.go.dev/fyne.io/systray?tab=doc) as well as [CHANGELOG](https://github.com/fyne-io/systray/tree/master/CHANGELOG.md).
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:
```sh
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](example/screenshot.png)
## 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](https://git.sr.ht/~steef/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:
```sh
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:
```xml
<!-- 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](https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1).
On macOS, it's possible to set the underlying
[`NSStatusItemBehavior`](https://developer.apple.com/documentation/appkit/nsstatusitembehavior?language=objc)
with `systray.SetRemovalAllowed(true)`. When enabled, the user can cmd-drag the
icon off the menu bar.
## Credits
- https://github.com/getlantern/systray
- https://github.com/xilp/systray
- https://github.com/cratonica/trayhost

View File

@@ -0,0 +1,484 @@
// Code generated by dbus-codegen-go DO NOT EDIT.
package menu
import (
"context"
"errors"
"fmt"
"github.com/godbus/dbus/v5"
"github.com/godbus/dbus/v5/introspect"
)
var (
// Introspection for com.canonical.dbusmenu
IntrospectDataDbusmenu = introspect.Interface{
Name: "com.canonical.dbusmenu",
Methods: []introspect.Method{{Name: "GetLayout", Args: []introspect.Arg{
{Name: "parentId", Type: "i", Direction: "in"},
{Name: "recursionDepth", Type: "i", Direction: "in"},
{Name: "propertyNames", Type: "as", Direction: "in"},
{Name: "revision", Type: "u", Direction: "out"},
{Name: "layout", Type: "(ia{sv}av)", Direction: "out"},
}},
{Name: "GetGroupProperties", Args: []introspect.Arg{
{Name: "ids", Type: "ai", Direction: "in"},
{Name: "propertyNames", Type: "as", Direction: "in"},
{Name: "properties", Type: "a(ia{sv})", Direction: "out"},
}},
{Name: "GetProperty", Args: []introspect.Arg{
{Name: "id", Type: "i", Direction: "in"},
{Name: "name", Type: "s", Direction: "in"},
{Name: "value", Type: "v", Direction: "out"},
}},
{Name: "Event", Args: []introspect.Arg{
{Name: "id", Type: "i", Direction: "in"},
{Name: "eventId", Type: "s", Direction: "in"},
{Name: "data", Type: "v", Direction: "in"},
{Name: "timestamp", Type: "u", Direction: "in"},
}},
{Name: "EventGroup", Args: []introspect.Arg{
{Name: "events", Type: "a(isvu)", Direction: "in"},
{Name: "idErrors", Type: "ai", Direction: "out"},
}},
{Name: "AboutToShow", Args: []introspect.Arg{
{Name: "id", Type: "i", Direction: "in"},
{Name: "needUpdate", Type: "b", Direction: "out"},
}},
{Name: "AboutToShowGroup", Args: []introspect.Arg{
{Name: "ids", Type: "ai", Direction: "in"},
{Name: "updatesNeeded", Type: "ai", Direction: "out"},
{Name: "idErrors", Type: "ai", Direction: "out"},
}},
},
Signals: []introspect.Signal{{Name: "ItemsPropertiesUpdated", Args: []introspect.Arg{
{Name: "updatedProps", Type: "a(ia{sv})", Direction: "out"},
{Name: "removedProps", Type: "a(ias)", Direction: "out"},
}},
{Name: "LayoutUpdated", Args: []introspect.Arg{
{Name: "revision", Type: "u", Direction: "out"},
{Name: "parent", Type: "i", Direction: "out"},
}},
{Name: "ItemActivationRequested", Args: []introspect.Arg{
{Name: "id", Type: "i", Direction: "out"},
{Name: "timestamp", Type: "u", Direction: "out"},
}},
},
Properties: []introspect.Property{{Name: "Version", Type: "u", Access: "read"},
{Name: "TextDirection", Type: "s", Access: "read"},
{Name: "Status", Type: "s", Access: "read"},
{Name: "IconThemePath", Type: "as", Access: "read"},
},
Annotations: []introspect.Annotation{},
}
)
// Signal is a common interface for all signals.
type Signal interface {
Name() string
Interface() string
Sender() string
path() dbus.ObjectPath
values() []interface{}
}
// Emit sends the given signal to the bus.
func Emit(conn *dbus.Conn, s Signal) error {
return conn.Emit(s.path(), s.Interface()+"."+s.Name(), s.values()...)
}
// ErrUnknownSignal is returned by LookupSignal when a signal cannot be resolved.
var ErrUnknownSignal = errors.New("unknown signal")
// LookupSignal converts the given raw D-Bus signal with variable body
// into one with typed structured body or returns ErrUnknownSignal error.
func LookupSignal(signal *dbus.Signal) (Signal, error) {
switch signal.Name {
case InterfaceDbusmenu + "." + "ItemsPropertiesUpdated":
v0, ok := signal.Body[0].([]struct {
V0 int32
V1 map[string]dbus.Variant
})
if !ok {
return nil, fmt.Errorf("prop .UpdatedProps is %T, not []struct {V0 int32;V1 map[string]dbus.Variant}", signal.Body[0])
}
v1, ok := signal.Body[1].([]struct {
V0 int32
V1 []string
})
if !ok {
return nil, fmt.Errorf("prop .RemovedProps is %T, not []struct {V0 int32;V1 []string}", signal.Body[1])
}
return &Dbusmenu_ItemsPropertiesUpdatedSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &Dbusmenu_ItemsPropertiesUpdatedSignalBody{
UpdatedProps: v0,
RemovedProps: v1,
},
}, nil
case InterfaceDbusmenu + "." + "LayoutUpdated":
v0, ok := signal.Body[0].(uint32)
if !ok {
return nil, fmt.Errorf("prop .Revision is %T, not uint32", signal.Body[0])
}
v1, ok := signal.Body[1].(int32)
if !ok {
return nil, fmt.Errorf("prop .Parent is %T, not int32", signal.Body[1])
}
return &Dbusmenu_LayoutUpdatedSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &Dbusmenu_LayoutUpdatedSignalBody{
Revision: v0,
Parent: v1,
},
}, nil
case InterfaceDbusmenu + "." + "ItemActivationRequested":
v0, ok := signal.Body[0].(int32)
if !ok {
return nil, fmt.Errorf("prop .Id is %T, not int32", signal.Body[0])
}
v1, ok := signal.Body[1].(uint32)
if !ok {
return nil, fmt.Errorf("prop .Timestamp is %T, not uint32", signal.Body[1])
}
return &Dbusmenu_ItemActivationRequestedSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &Dbusmenu_ItemActivationRequestedSignalBody{
Id: v0,
Timestamp: v1,
},
}, nil
default:
return nil, ErrUnknownSignal
}
}
// AddMatchSignal registers a match rule for the given signal,
// opts are appended to the automatically generated signal's rules.
func AddMatchSignal(conn *dbus.Conn, s Signal, opts ...dbus.MatchOption) error {
return conn.AddMatchSignal(append([]dbus.MatchOption{
dbus.WithMatchInterface(s.Interface()),
dbus.WithMatchMember(s.Name()),
}, opts...)...)
}
// RemoveMatchSignal unregisters the previously registered subscription.
func RemoveMatchSignal(conn *dbus.Conn, s Signal, opts ...dbus.MatchOption) error {
return conn.RemoveMatchSignal(append([]dbus.MatchOption{
dbus.WithMatchInterface(s.Interface()),
dbus.WithMatchMember(s.Name()),
}, opts...)...)
}
// Interface name constants.
const (
InterfaceDbusmenu = "com.canonical.dbusmenu"
)
// Dbusmenuer is com.canonical.dbusmenu interface.
type Dbusmenuer interface {
// GetLayout is com.canonical.dbusmenu.GetLayout method.
GetLayout(parentId int32, recursionDepth int32, propertyNames []string) (revision uint32, layout struct {
V0 int32
V1 map[string]dbus.Variant
V2 []dbus.Variant
}, err *dbus.Error)
// GetGroupProperties is com.canonical.dbusmenu.GetGroupProperties method.
GetGroupProperties(ids []int32, propertyNames []string) (properties []struct {
V0 int32
V1 map[string]dbus.Variant
}, err *dbus.Error)
// GetProperty is com.canonical.dbusmenu.GetProperty method.
GetProperty(id int32, name string) (value dbus.Variant, err *dbus.Error)
// Event is com.canonical.dbusmenu.Event method.
Event(id int32, eventId string, data dbus.Variant, timestamp uint32) (err *dbus.Error)
// EventGroup is com.canonical.dbusmenu.EventGroup method.
EventGroup(events []struct {
V0 int32
V1 string
V2 dbus.Variant
V3 uint32
}) (idErrors []int32, err *dbus.Error)
// AboutToShow is com.canonical.dbusmenu.AboutToShow method.
AboutToShow(id int32) (needUpdate bool, err *dbus.Error)
// AboutToShowGroup is com.canonical.dbusmenu.AboutToShowGroup method.
AboutToShowGroup(ids []int32) (updatesNeeded []int32, idErrors []int32, err *dbus.Error)
}
// ExportDbusmenu exports the given object that implements com.canonical.dbusmenu on the bus.
func ExportDbusmenu(conn *dbus.Conn, path dbus.ObjectPath, v Dbusmenuer) error {
return conn.ExportSubtreeMethodTable(map[string]interface{}{
"GetLayout": v.GetLayout,
"GetGroupProperties": v.GetGroupProperties,
"GetProperty": v.GetProperty,
"Event": v.Event,
"EventGroup": v.EventGroup,
"AboutToShow": v.AboutToShow,
"AboutToShowGroup": v.AboutToShowGroup,
}, path, InterfaceDbusmenu)
}
// UnexportDbusmenu unexports com.canonical.dbusmenu interface on the named path.
func UnexportDbusmenu(conn *dbus.Conn, path dbus.ObjectPath) error {
return conn.Export(nil, path, InterfaceDbusmenu)
}
// UnimplementedDbusmenu can be embedded to have forward compatible server implementations.
type UnimplementedDbusmenu struct{}
func (*UnimplementedDbusmenu) iface() string {
return InterfaceDbusmenu
}
func (*UnimplementedDbusmenu) GetLayout(parentId int32, recursionDepth int32, propertyNames []string) (revision uint32, layout struct {
V0 int32
V1 map[string]dbus.Variant
V2 []dbus.Variant
}, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) GetGroupProperties(ids []int32, propertyNames []string) (properties []struct {
V0 int32
V1 map[string]dbus.Variant
}, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) GetProperty(id int32, name string) (value dbus.Variant, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) Event(id int32, eventId string, data dbus.Variant, timestamp uint32) (err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) EventGroup(events []struct {
V0 int32
V1 string
V2 dbus.Variant
V3 uint32
}) (idErrors []int32, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) AboutToShow(id int32) (needUpdate bool, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) AboutToShowGroup(ids []int32) (updatesNeeded []int32, idErrors []int32, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
// NewDbusmenu creates and allocates com.canonical.dbusmenu.
func NewDbusmenu(object dbus.BusObject) *Dbusmenu {
return &Dbusmenu{object}
}
// Dbusmenu implements com.canonical.dbusmenu D-Bus interface.
type Dbusmenu struct {
object dbus.BusObject
}
// GetLayout calls com.canonical.dbusmenu.GetLayout method.
func (o *Dbusmenu) GetLayout(ctx context.Context, parentId int32, recursionDepth int32, propertyNames []string) (revision uint32, layout struct {
V0 int32
V1 map[string]dbus.Variant
V2 []dbus.Variant
}, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".GetLayout", 0, parentId, recursionDepth, propertyNames).Store(&revision, &layout)
return
}
// GetGroupProperties calls com.canonical.dbusmenu.GetGroupProperties method.
func (o *Dbusmenu) GetGroupProperties(ctx context.Context, ids []int32, propertyNames []string) (properties []struct {
V0 int32
V1 map[string]dbus.Variant
}, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".GetGroupProperties", 0, ids, propertyNames).Store(&properties)
return
}
// GetProperty calls com.canonical.dbusmenu.GetProperty method.
func (o *Dbusmenu) GetProperty(ctx context.Context, id int32, name string) (value dbus.Variant, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".GetProperty", 0, id, name).Store(&value)
return
}
// Event calls com.canonical.dbusmenu.Event method.
func (o *Dbusmenu) Event(ctx context.Context, id int32, eventId string, data dbus.Variant, timestamp uint32) (err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".Event", 0, id, eventId, data, timestamp).Store()
return
}
// EventGroup calls com.canonical.dbusmenu.EventGroup method.
func (o *Dbusmenu) EventGroup(ctx context.Context, events []struct {
V0 int32
V1 string
V2 dbus.Variant
V3 uint32
}) (idErrors []int32, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".EventGroup", 0, events).Store(&idErrors)
return
}
// AboutToShow calls com.canonical.dbusmenu.AboutToShow method.
func (o *Dbusmenu) AboutToShow(ctx context.Context, id int32) (needUpdate bool, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".AboutToShow", 0, id).Store(&needUpdate)
return
}
// AboutToShowGroup calls com.canonical.dbusmenu.AboutToShowGroup method.
func (o *Dbusmenu) AboutToShowGroup(ctx context.Context, ids []int32) (updatesNeeded []int32, idErrors []int32, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".AboutToShowGroup", 0, ids).Store(&updatesNeeded, &idErrors)
return
}
// GetVersion gets com.canonical.dbusmenu.Version property.
func (o *Dbusmenu) GetVersion(ctx context.Context) (version uint32, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceDbusmenu, "Version").Store(&version)
return
}
// GetTextDirection gets com.canonical.dbusmenu.TextDirection property.
func (o *Dbusmenu) GetTextDirection(ctx context.Context) (textDirection string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceDbusmenu, "TextDirection").Store(&textDirection)
return
}
// GetStatus gets com.canonical.dbusmenu.Status property.
func (o *Dbusmenu) GetStatus(ctx context.Context) (status string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceDbusmenu, "Status").Store(&status)
return
}
// GetIconThemePath gets com.canonical.dbusmenu.IconThemePath property.
func (o *Dbusmenu) GetIconThemePath(ctx context.Context) (iconThemePath []string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceDbusmenu, "IconThemePath").Store(&iconThemePath)
return
}
// Dbusmenu_ItemsPropertiesUpdatedSignal represents com.canonical.dbusmenu.ItemsPropertiesUpdated signal.
type Dbusmenu_ItemsPropertiesUpdatedSignal struct {
sender string
Path dbus.ObjectPath
Body *Dbusmenu_ItemsPropertiesUpdatedSignalBody
}
// Name returns the signal's name.
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) Name() string {
return "ItemsPropertiesUpdated"
}
// Interface returns the signal's interface.
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) Interface() string {
return InterfaceDbusmenu
}
// Sender returns the signal's sender unique name.
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) Sender() string {
return s.sender
}
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) values() []interface{} {
return []interface{}{s.Body.UpdatedProps, s.Body.RemovedProps}
}
// Dbusmenu_ItemsPropertiesUpdatedSignalBody is body container.
type Dbusmenu_ItemsPropertiesUpdatedSignalBody struct {
UpdatedProps []struct {
V0 int32
V1 map[string]dbus.Variant
}
RemovedProps []struct {
V0 int32
V1 []string
}
}
// Dbusmenu_LayoutUpdatedSignal represents com.canonical.dbusmenu.LayoutUpdated signal.
type Dbusmenu_LayoutUpdatedSignal struct {
sender string
Path dbus.ObjectPath
Body *Dbusmenu_LayoutUpdatedSignalBody
}
// Name returns the signal's name.
func (s *Dbusmenu_LayoutUpdatedSignal) Name() string {
return "LayoutUpdated"
}
// Interface returns the signal's interface.
func (s *Dbusmenu_LayoutUpdatedSignal) Interface() string {
return InterfaceDbusmenu
}
// Sender returns the signal's sender unique name.
func (s *Dbusmenu_LayoutUpdatedSignal) Sender() string {
return s.sender
}
func (s *Dbusmenu_LayoutUpdatedSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *Dbusmenu_LayoutUpdatedSignal) values() []interface{} {
return []interface{}{s.Body.Revision, s.Body.Parent}
}
// Dbusmenu_LayoutUpdatedSignalBody is body container.
type Dbusmenu_LayoutUpdatedSignalBody struct {
Revision uint32
Parent int32
}
// Dbusmenu_ItemActivationRequestedSignal represents com.canonical.dbusmenu.ItemActivationRequested signal.
type Dbusmenu_ItemActivationRequestedSignal struct {
sender string
Path dbus.ObjectPath
Body *Dbusmenu_ItemActivationRequestedSignalBody
}
// Name returns the signal's name.
func (s *Dbusmenu_ItemActivationRequestedSignal) Name() string {
return "ItemActivationRequested"
}
// Interface returns the signal's interface.
func (s *Dbusmenu_ItemActivationRequestedSignal) Interface() string {
return InterfaceDbusmenu
}
// Sender returns the signal's sender unique name.
func (s *Dbusmenu_ItemActivationRequestedSignal) Sender() string {
return s.sender
}
func (s *Dbusmenu_ItemActivationRequestedSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *Dbusmenu_ItemActivationRequestedSignal) values() []interface{} {
return []interface{}{s.Body.Id, s.Body.Timestamp}
}
// Dbusmenu_ItemActivationRequestedSignalBody is body container.
type Dbusmenu_ItemActivationRequestedSignalBody struct {
Id int32
Timestamp uint32
}

View File

@@ -0,0 +1,633 @@
// Code generated by dbus-codegen-go DO NOT EDIT.
package notifier
import (
"context"
"errors"
"fmt"
"github.com/godbus/dbus/v5"
"github.com/godbus/dbus/v5/introspect"
)
var (
// Introspection for org.kde.StatusNotifierItem
IntrospectDataStatusNotifierItem = introspect.Interface{
Name: "org.kde.StatusNotifierItem",
Methods: []introspect.Method{{Name: "ContextMenu", Args: []introspect.Arg{
{Name: "x", Type: "i", Direction: "in"},
{Name: "y", Type: "i", Direction: "in"},
}},
{Name: "Activate", Args: []introspect.Arg{
{Name: "x", Type: "i", Direction: "in"},
{Name: "y", Type: "i", Direction: "in"},
}},
{Name: "SecondaryActivate", Args: []introspect.Arg{
{Name: "x", Type: "i", Direction: "in"},
{Name: "y", Type: "i", Direction: "in"},
}},
{Name: "Scroll", Args: []introspect.Arg{
{Name: "delta", Type: "i", Direction: "in"},
{Name: "orientation", Type: "s", Direction: "in"},
}},
},
Signals: []introspect.Signal{{Name: "NewTitle"},
{Name: "NewIcon"},
{Name: "NewAttentionIcon"},
{Name: "NewOverlayIcon"},
{Name: "NewStatus", Args: []introspect.Arg{
{Name: "status", Type: "s", Direction: ""},
}},
{Name: "NewIconThemePath", Args: []introspect.Arg{
{Name: "icon_theme_path", Type: "s", Direction: "out"},
}},
{Name: "NewMenu"},
},
Properties: []introspect.Property{{Name: "Category", Type: "s", Access: "read"},
{Name: "Id", Type: "s", Access: "read"},
{Name: "Title", Type: "s", Access: "read"},
{Name: "Status", Type: "s", Access: "read"},
{Name: "WindowId", Type: "i", Access: "read"},
{Name: "IconThemePath", Type: "s", Access: "read"},
{Name: "Menu", Type: "o", Access: "read"},
{Name: "ItemIsMenu", Type: "b", Access: "read"},
{Name: "IconName", Type: "s", Access: "read"},
{Name: "IconPixmap", Type: "a(iiay)", Access: "read", Annotations: []introspect.Annotation{
{Name: "org.qtproject.QtDBus.QtTypeName", Value: "KDbusImageVector"},
}},
{Name: "OverlayIconName", Type: "s", Access: "read"},
{Name: "OverlayIconPixmap", Type: "a(iiay)", Access: "read", Annotations: []introspect.Annotation{
{Name: "org.qtproject.QtDBus.QtTypeName", Value: "KDbusImageVector"},
}},
{Name: "AttentionIconName", Type: "s", Access: "read"},
{Name: "AttentionIconPixmap", Type: "a(iiay)", Access: "read", Annotations: []introspect.Annotation{
{Name: "org.qtproject.QtDBus.QtTypeName", Value: "KDbusImageVector"},
}},
{Name: "AttentionMovieName", Type: "s", Access: "read"},
{Name: "ToolTip", Type: "(sa(iiay)ss)", Access: "read", Annotations: []introspect.Annotation{
{Name: "org.qtproject.QtDBus.QtTypeName", Value: "KDbusToolTipStruct"},
}},
},
Annotations: []introspect.Annotation{},
}
)
// Signal is a common interface for all signals.
type Signal interface {
Name() string
Interface() string
Sender() string
path() dbus.ObjectPath
values() []interface{}
}
// Emit sends the given signal to the bus.
func Emit(conn *dbus.Conn, s Signal) error {
return conn.Emit(s.path(), s.Interface()+"."+s.Name(), s.values()...)
}
// ErrUnknownSignal is returned by LookupSignal when a signal cannot be resolved.
var ErrUnknownSignal = errors.New("unknown signal")
// LookupSignal converts the given raw D-Bus signal with variable body
// into one with typed structured body or returns ErrUnknownSignal error.
func LookupSignal(signal *dbus.Signal) (Signal, error) {
switch signal.Name {
case InterfaceStatusNotifierItem + "." + "NewTitle":
return &StatusNotifierItem_NewTitleSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &StatusNotifierItem_NewTitleSignalBody{},
}, nil
case InterfaceStatusNotifierItem + "." + "NewIcon":
return &StatusNotifierItem_NewIconSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &StatusNotifierItem_NewIconSignalBody{},
}, nil
case InterfaceStatusNotifierItem + "." + "NewAttentionIcon":
return &StatusNotifierItem_NewAttentionIconSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &StatusNotifierItem_NewAttentionIconSignalBody{},
}, nil
case InterfaceStatusNotifierItem + "." + "NewOverlayIcon":
return &StatusNotifierItem_NewOverlayIconSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &StatusNotifierItem_NewOverlayIconSignalBody{},
}, nil
case InterfaceStatusNotifierItem + "." + "NewStatus":
v0, ok := signal.Body[0].(string)
if !ok {
return nil, fmt.Errorf("prop .Status is %T, not string", signal.Body[0])
}
return &StatusNotifierItem_NewStatusSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &StatusNotifierItem_NewStatusSignalBody{
Status: v0,
},
}, nil
case InterfaceStatusNotifierItem + "." + "NewIconThemePath":
v0, ok := signal.Body[0].(string)
if !ok {
return nil, fmt.Errorf("prop .IconThemePath is %T, not string", signal.Body[0])
}
return &StatusNotifierItem_NewIconThemePathSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &StatusNotifierItem_NewIconThemePathSignalBody{
IconThemePath: v0,
},
}, nil
case InterfaceStatusNotifierItem + "." + "NewMenu":
return &StatusNotifierItem_NewMenuSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &StatusNotifierItem_NewMenuSignalBody{},
}, nil
default:
return nil, ErrUnknownSignal
}
}
// AddMatchSignal registers a match rule for the given signal,
// opts are appended to the automatically generated signal's rules.
func AddMatchSignal(conn *dbus.Conn, s Signal, opts ...dbus.MatchOption) error {
return conn.AddMatchSignal(append([]dbus.MatchOption{
dbus.WithMatchInterface(s.Interface()),
dbus.WithMatchMember(s.Name()),
}, opts...)...)
}
// RemoveMatchSignal unregisters the previously registered subscription.
func RemoveMatchSignal(conn *dbus.Conn, s Signal, opts ...dbus.MatchOption) error {
return conn.RemoveMatchSignal(append([]dbus.MatchOption{
dbus.WithMatchInterface(s.Interface()),
dbus.WithMatchMember(s.Name()),
}, opts...)...)
}
// Interface name constants.
const (
InterfaceStatusNotifierItem = "org.kde.StatusNotifierItem"
)
// StatusNotifierItemer is org.kde.StatusNotifierItem interface.
type StatusNotifierItemer interface {
// ContextMenu is org.kde.StatusNotifierItem.ContextMenu method.
ContextMenu(x int32, y int32) (err *dbus.Error)
// Activate is org.kde.StatusNotifierItem.Activate method.
Activate(x int32, y int32) (err *dbus.Error)
// SecondaryActivate is org.kde.StatusNotifierItem.SecondaryActivate method.
SecondaryActivate(x int32, y int32) (err *dbus.Error)
// Scroll is org.kde.StatusNotifierItem.Scroll method.
Scroll(delta int32, orientation string) (err *dbus.Error)
}
// ExportStatusNotifierItem exports the given object that implements org.kde.StatusNotifierItem on the bus.
func ExportStatusNotifierItem(conn *dbus.Conn, path dbus.ObjectPath, v StatusNotifierItemer) error {
return conn.ExportSubtreeMethodTable(map[string]interface{}{
"ContextMenu": v.ContextMenu,
"Activate": v.Activate,
"SecondaryActivate": v.SecondaryActivate,
"Scroll": v.Scroll,
}, path, InterfaceStatusNotifierItem)
}
// UnexportStatusNotifierItem unexports org.kde.StatusNotifierItem interface on the named path.
func UnexportStatusNotifierItem(conn *dbus.Conn, path dbus.ObjectPath) error {
return conn.Export(nil, path, InterfaceStatusNotifierItem)
}
// UnimplementedStatusNotifierItem can be embedded to have forward compatible server implementations.
type UnimplementedStatusNotifierItem struct{}
func (*UnimplementedStatusNotifierItem) iface() string {
return InterfaceStatusNotifierItem
}
func (*UnimplementedStatusNotifierItem) ContextMenu(x int32, y int32) (err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedStatusNotifierItem) Activate(x int32, y int32) (err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedStatusNotifierItem) SecondaryActivate(x int32, y int32) (err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedStatusNotifierItem) Scroll(delta int32, orientation string) (err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
// NewStatusNotifierItem creates and allocates org.kde.StatusNotifierItem.
func NewStatusNotifierItem(object dbus.BusObject) *StatusNotifierItem {
return &StatusNotifierItem{object}
}
// StatusNotifierItem implements org.kde.StatusNotifierItem D-Bus interface.
type StatusNotifierItem struct {
object dbus.BusObject
}
// ContextMenu calls org.kde.StatusNotifierItem.ContextMenu method.
func (o *StatusNotifierItem) ContextMenu(ctx context.Context, x int32, y int32) (err error) {
err = o.object.CallWithContext(ctx, InterfaceStatusNotifierItem+".ContextMenu", 0, x, y).Store()
return
}
// Activate calls org.kde.StatusNotifierItem.Activate method.
func (o *StatusNotifierItem) Activate(ctx context.Context, x int32, y int32) (err error) {
err = o.object.CallWithContext(ctx, InterfaceStatusNotifierItem+".Activate", 0, x, y).Store()
return
}
// SecondaryActivate calls org.kde.StatusNotifierItem.SecondaryActivate method.
func (o *StatusNotifierItem) SecondaryActivate(ctx context.Context, x int32, y int32) (err error) {
err = o.object.CallWithContext(ctx, InterfaceStatusNotifierItem+".SecondaryActivate", 0, x, y).Store()
return
}
// Scroll calls org.kde.StatusNotifierItem.Scroll method.
func (o *StatusNotifierItem) Scroll(ctx context.Context, delta int32, orientation string) (err error) {
err = o.object.CallWithContext(ctx, InterfaceStatusNotifierItem+".Scroll", 0, delta, orientation).Store()
return
}
// GetCategory gets org.kde.StatusNotifierItem.Category property.
func (o *StatusNotifierItem) GetCategory(ctx context.Context) (category string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "Category").Store(&category)
return
}
// GetId gets org.kde.StatusNotifierItem.Id property.
func (o *StatusNotifierItem) GetId(ctx context.Context) (id string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "Id").Store(&id)
return
}
// GetTitle gets org.kde.StatusNotifierItem.Title property.
func (o *StatusNotifierItem) GetTitle(ctx context.Context) (title string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "Title").Store(&title)
return
}
// GetStatus gets org.kde.StatusNotifierItem.Status property.
func (o *StatusNotifierItem) GetStatus(ctx context.Context) (status string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "Status").Store(&status)
return
}
// GetWindowId gets org.kde.StatusNotifierItem.WindowId property.
func (o *StatusNotifierItem) GetWindowId(ctx context.Context) (windowId int32, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "WindowId").Store(&windowId)
return
}
// GetIconThemePath gets org.kde.StatusNotifierItem.IconThemePath property.
func (o *StatusNotifierItem) GetIconThemePath(ctx context.Context) (iconThemePath string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "IconThemePath").Store(&iconThemePath)
return
}
// GetMenu gets org.kde.StatusNotifierItem.Menu property.
func (o *StatusNotifierItem) GetMenu(ctx context.Context) (menu dbus.ObjectPath, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "Menu").Store(&menu)
return
}
// GetItemIsMenu gets org.kde.StatusNotifierItem.ItemIsMenu property.
func (o *StatusNotifierItem) GetItemIsMenu(ctx context.Context) (itemIsMenu bool, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "ItemIsMenu").Store(&itemIsMenu)
return
}
// GetIconName gets org.kde.StatusNotifierItem.IconName property.
func (o *StatusNotifierItem) GetIconName(ctx context.Context) (iconName string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "IconName").Store(&iconName)
return
}
// GetIconPixmap gets org.kde.StatusNotifierItem.IconPixmap property.
//
// Annotations:
// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector
func (o *StatusNotifierItem) GetIconPixmap(ctx context.Context) (iconPixmap []struct {
V0 int32
V1 int32
V2 []byte
}, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "IconPixmap").Store(&iconPixmap)
return
}
// GetOverlayIconName gets org.kde.StatusNotifierItem.OverlayIconName property.
func (o *StatusNotifierItem) GetOverlayIconName(ctx context.Context) (overlayIconName string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "OverlayIconName").Store(&overlayIconName)
return
}
// GetOverlayIconPixmap gets org.kde.StatusNotifierItem.OverlayIconPixmap property.
//
// Annotations:
// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector
func (o *StatusNotifierItem) GetOverlayIconPixmap(ctx context.Context) (overlayIconPixmap []struct {
V0 int32
V1 int32
V2 []byte
}, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "OverlayIconPixmap").Store(&overlayIconPixmap)
return
}
// GetAttentionIconName gets org.kde.StatusNotifierItem.AttentionIconName property.
func (o *StatusNotifierItem) GetAttentionIconName(ctx context.Context) (attentionIconName string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "AttentionIconName").Store(&attentionIconName)
return
}
// GetAttentionIconPixmap gets org.kde.StatusNotifierItem.AttentionIconPixmap property.
//
// Annotations:
// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector
func (o *StatusNotifierItem) GetAttentionIconPixmap(ctx context.Context) (attentionIconPixmap []struct {
V0 int32
V1 int32
V2 []byte
}, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "AttentionIconPixmap").Store(&attentionIconPixmap)
return
}
// GetAttentionMovieName gets org.kde.StatusNotifierItem.AttentionMovieName property.
func (o *StatusNotifierItem) GetAttentionMovieName(ctx context.Context) (attentionMovieName string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "AttentionMovieName").Store(&attentionMovieName)
return
}
// GetToolTip gets org.kde.StatusNotifierItem.ToolTip property.
//
// Annotations:
// @org.qtproject.QtDBus.QtTypeName = KDbusToolTipStruct
func (o *StatusNotifierItem) GetToolTip(ctx context.Context) (toolTip struct {
V0 string
V1 []struct {
V0 int32
V1 int32
V2 []byte
}
V2 string
V3 string
}, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierItem, "ToolTip").Store(&toolTip)
return
}
// StatusNotifierItem_NewTitleSignal represents org.kde.StatusNotifierItem.NewTitle signal.
type StatusNotifierItem_NewTitleSignal struct {
sender string
Path dbus.ObjectPath
Body *StatusNotifierItem_NewTitleSignalBody
}
// Name returns the signal's name.
func (s *StatusNotifierItem_NewTitleSignal) Name() string {
return "NewTitle"
}
// Interface returns the signal's interface.
func (s *StatusNotifierItem_NewTitleSignal) Interface() string {
return InterfaceStatusNotifierItem
}
// Sender returns the signal's sender unique name.
func (s *StatusNotifierItem_NewTitleSignal) Sender() string {
return s.sender
}
func (s *StatusNotifierItem_NewTitleSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *StatusNotifierItem_NewTitleSignal) values() []interface{} {
return []interface{}{}
}
// StatusNotifierItem_NewTitleSignalBody is body container.
type StatusNotifierItem_NewTitleSignalBody struct {
}
// StatusNotifierItem_NewIconSignal represents org.kde.StatusNotifierItem.NewIcon signal.
type StatusNotifierItem_NewIconSignal struct {
sender string
Path dbus.ObjectPath
Body *StatusNotifierItem_NewIconSignalBody
}
// Name returns the signal's name.
func (s *StatusNotifierItem_NewIconSignal) Name() string {
return "NewIcon"
}
// Interface returns the signal's interface.
func (s *StatusNotifierItem_NewIconSignal) Interface() string {
return InterfaceStatusNotifierItem
}
// Sender returns the signal's sender unique name.
func (s *StatusNotifierItem_NewIconSignal) Sender() string {
return s.sender
}
func (s *StatusNotifierItem_NewIconSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *StatusNotifierItem_NewIconSignal) values() []interface{} {
return []interface{}{}
}
// StatusNotifierItem_NewIconSignalBody is body container.
type StatusNotifierItem_NewIconSignalBody struct {
}
// StatusNotifierItem_NewAttentionIconSignal represents org.kde.StatusNotifierItem.NewAttentionIcon signal.
type StatusNotifierItem_NewAttentionIconSignal struct {
sender string
Path dbus.ObjectPath
Body *StatusNotifierItem_NewAttentionIconSignalBody
}
// Name returns the signal's name.
func (s *StatusNotifierItem_NewAttentionIconSignal) Name() string {
return "NewAttentionIcon"
}
// Interface returns the signal's interface.
func (s *StatusNotifierItem_NewAttentionIconSignal) Interface() string {
return InterfaceStatusNotifierItem
}
// Sender returns the signal's sender unique name.
func (s *StatusNotifierItem_NewAttentionIconSignal) Sender() string {
return s.sender
}
func (s *StatusNotifierItem_NewAttentionIconSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *StatusNotifierItem_NewAttentionIconSignal) values() []interface{} {
return []interface{}{}
}
// StatusNotifierItem_NewAttentionIconSignalBody is body container.
type StatusNotifierItem_NewAttentionIconSignalBody struct {
}
// StatusNotifierItem_NewOverlayIconSignal represents org.kde.StatusNotifierItem.NewOverlayIcon signal.
type StatusNotifierItem_NewOverlayIconSignal struct {
sender string
Path dbus.ObjectPath
Body *StatusNotifierItem_NewOverlayIconSignalBody
}
// Name returns the signal's name.
func (s *StatusNotifierItem_NewOverlayIconSignal) Name() string {
return "NewOverlayIcon"
}
// Interface returns the signal's interface.
func (s *StatusNotifierItem_NewOverlayIconSignal) Interface() string {
return InterfaceStatusNotifierItem
}
// Sender returns the signal's sender unique name.
func (s *StatusNotifierItem_NewOverlayIconSignal) Sender() string {
return s.sender
}
func (s *StatusNotifierItem_NewOverlayIconSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *StatusNotifierItem_NewOverlayIconSignal) values() []interface{} {
return []interface{}{}
}
// StatusNotifierItem_NewOverlayIconSignalBody is body container.
type StatusNotifierItem_NewOverlayIconSignalBody struct {
}
// StatusNotifierItem_NewStatusSignal represents org.kde.StatusNotifierItem.NewStatus signal.
type StatusNotifierItem_NewStatusSignal struct {
sender string
Path dbus.ObjectPath
Body *StatusNotifierItem_NewStatusSignalBody
}
// Name returns the signal's name.
func (s *StatusNotifierItem_NewStatusSignal) Name() string {
return "NewStatus"
}
// Interface returns the signal's interface.
func (s *StatusNotifierItem_NewStatusSignal) Interface() string {
return InterfaceStatusNotifierItem
}
// Sender returns the signal's sender unique name.
func (s *StatusNotifierItem_NewStatusSignal) Sender() string {
return s.sender
}
func (s *StatusNotifierItem_NewStatusSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *StatusNotifierItem_NewStatusSignal) values() []interface{} {
return []interface{}{s.Body.Status}
}
// StatusNotifierItem_NewStatusSignalBody is body container.
type StatusNotifierItem_NewStatusSignalBody struct {
Status string
}
// StatusNotifierItem_NewIconThemePathSignal represents org.kde.StatusNotifierItem.NewIconThemePath signal.
type StatusNotifierItem_NewIconThemePathSignal struct {
sender string
Path dbus.ObjectPath
Body *StatusNotifierItem_NewIconThemePathSignalBody
}
// Name returns the signal's name.
func (s *StatusNotifierItem_NewIconThemePathSignal) Name() string {
return "NewIconThemePath"
}
// Interface returns the signal's interface.
func (s *StatusNotifierItem_NewIconThemePathSignal) Interface() string {
return InterfaceStatusNotifierItem
}
// Sender returns the signal's sender unique name.
func (s *StatusNotifierItem_NewIconThemePathSignal) Sender() string {
return s.sender
}
func (s *StatusNotifierItem_NewIconThemePathSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *StatusNotifierItem_NewIconThemePathSignal) values() []interface{} {
return []interface{}{s.Body.IconThemePath}
}
// StatusNotifierItem_NewIconThemePathSignalBody is body container.
type StatusNotifierItem_NewIconThemePathSignalBody struct {
IconThemePath string
}
// StatusNotifierItem_NewMenuSignal represents org.kde.StatusNotifierItem.NewMenu signal.
type StatusNotifierItem_NewMenuSignal struct {
sender string
Path dbus.ObjectPath
Body *StatusNotifierItem_NewMenuSignalBody
}
// Name returns the signal's name.
func (s *StatusNotifierItem_NewMenuSignal) Name() string {
return "NewMenu"
}
// Interface returns the signal's interface.
func (s *StatusNotifierItem_NewMenuSignal) Interface() string {
return InterfaceStatusNotifierItem
}
// Sender returns the signal's sender unique name.
func (s *StatusNotifierItem_NewMenuSignal) Sender() string {
return s.sender
}
func (s *StatusNotifierItem_NewMenuSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *StatusNotifierItem_NewMenuSignal) values() []interface{} {
return []interface{}{}
}
// StatusNotifierItem_NewMenuSignalBody is body container.
type StatusNotifierItem_NewMenuSignalBody struct {
}

311
vendor/fyne.io/systray/systray.go generated vendored Normal file
View File

@@ -0,0 +1,311 @@
// Package systray is a cross-platform Go library to place an icon and menu in the notification area.
package systray
import (
"fmt"
"log"
"runtime"
"sync"
"sync/atomic"
)
var (
systrayReady, systrayExit func()
tappedLeft, tappedRight func()
systrayExitCalled bool
menuItems = make(map[uint32]*MenuItem)
menuItemsLock sync.RWMutex
initialMenuBuilt sync.WaitGroup
currentID atomic.Uint32
quitOnce sync.Once
// TrayOpenedCh receives an entry each time the system tray menu is opened.
TrayOpenedCh = make(chan struct{})
)
// This helper function allows us to call systrayExit only once,
// without accidentally calling it twice in the same lifetime.
func runSystrayExit() {
if !systrayExitCalled {
systrayExitCalled = true
systrayExit()
}
}
func init() {
runtime.LockOSThread()
}
// MenuItem is used to keep track each menu item of systray.
// Don't create it directly, use the one systray.AddMenuItem() returned
type MenuItem struct {
// ClickedCh is the channel which will be notified when the menu item is clicked
ClickedCh chan struct{}
// id uniquely identify a menu item, not supposed to be modified
id uint32
// title is the text shown on menu item
title string
// tooltip is the text shown when pointing to menu item
tooltip string
// disabled menu item is grayed out and has no effect when clicked
disabled bool
// checked menu item has a tick before the title
checked bool
// has the menu item a checkbox (Linux)
isCheckable bool
// parent item, for sub menus
parent *MenuItem
}
func (item *MenuItem) String() string {
if item.parent == nil {
return fmt.Sprintf("MenuItem[%d, %q]", item.id, item.title)
}
return fmt.Sprintf("MenuItem[%d, parent %d, %q]", item.id, item.parent.id, item.title)
}
// newMenuItem returns a populated MenuItem object
func newMenuItem(title string, tooltip string, parent *MenuItem) *MenuItem {
return &MenuItem{
ClickedCh: make(chan struct{}),
id: currentID.Add(1),
title: title,
tooltip: tooltip,
disabled: false,
checked: false,
isCheckable: false,
parent: parent,
}
}
// Run initializes GUI and starts the event loop, then invokes the onReady
// callback. It blocks until systray.Quit() is called.
func Run(onReady, onExit func()) {
setInternalLoop(true)
Register(onReady, onExit)
nativeLoop()
}
// RunWithExternalLoop allows the system tray module to operate with other toolkits.
// The returned start and end functions should be called by the toolkit when the application has started and will end.
func RunWithExternalLoop(onReady, onExit func()) (start, end func()) {
Register(onReady, onExit)
return nativeStart, func() {
nativeEnd()
Quit()
}
}
// Register initializes GUI and registers the callbacks but relies on the
// caller to run the event loop somewhere else. It's useful if the program
// needs to show other UI elements, for example, webview.
// To overcome some OS weirdness, On macOS versions before Catalina, calling
// this does exactly the same as Run().
func Register(onReady func(), onExit func()) {
if onReady == nil {
systrayReady = func() {}
} else {
// Run onReady on separate goroutine to avoid blocking event loop
readyCh := make(chan interface{})
initialMenuBuilt.Add(1)
go func() {
<-readyCh
onReady()
initialMenuBuilt.Done()
}()
systrayReady = func() {
close(readyCh)
}
}
// unlike onReady, onExit runs in the event loop to make sure it has time to
// finish before the process terminates
if onExit == nil {
onExit = func() {}
}
systrayExit = onExit
systrayExitCalled = false
registerSystray()
}
// ResetMenu will remove all menu items
func ResetMenu() {
menuItemsLock.Lock()
id := currentID.Load()
menuItemsLock.Unlock()
for i, item := range menuItems {
if i < id && item.parent == nil {
item.Remove()
}
}
resetMenu()
}
// Quit the systray
func Quit() {
quitOnce.Do(quit)
}
func SetOnTapped(f func()) {
tappedLeft = f
}
func SetOnSecondaryTapped(f func()) {
tappedRight = f
}
// AddMenuItem adds a menu item with the designated title and tooltip.
// It can be safely invoked from different goroutines.
// Created menu items are checkable on Windows and OSX by default. For Linux you have to use AddMenuItemCheckbox
func AddMenuItem(title string, tooltip string) *MenuItem {
item := newMenuItem(title, tooltip, nil)
item.update()
return item
}
// AddMenuItemCheckbox adds a menu item with the designated title and tooltip and a checkbox for Linux.
// On other platforms there will be a check indicated next to the item if `checked` is true.
// It can be safely invoked from different goroutines.
func AddMenuItemCheckbox(title string, tooltip string, checked bool) *MenuItem {
item := newMenuItem(title, tooltip, nil)
item.isCheckable = true
item.checked = checked
item.update()
return item
}
// AddSeparator adds a separator bar to the menu
func AddSeparator() {
addSeparator(currentID.Add(1), 0)
}
// AddSeparator adds a separator bar to the submenu
func (item *MenuItem) AddSeparator() {
addSeparator(currentID.Add(1), item.id)
}
// AddSubMenuItem adds a nested sub-menu item with the designated title and tooltip.
// It can be safely invoked from different goroutines.
// Created menu items are checkable on Windows and OSX by default. For Linux you have to use AddSubMenuItemCheckbox
func (item *MenuItem) AddSubMenuItem(title string, tooltip string) *MenuItem {
child := newMenuItem(title, tooltip, item)
child.update()
return child
}
// AddSubMenuItemCheckbox adds a nested sub-menu item with the designated title and tooltip and a checkbox for Linux.
// It can be safely invoked from different goroutines.
// On Windows and OSX this is the same as calling AddSubMenuItem
func (item *MenuItem) AddSubMenuItemCheckbox(title string, tooltip string, checked bool) *MenuItem {
child := newMenuItem(title, tooltip, item)
child.isCheckable = true
child.checked = checked
child.update()
return child
}
// SetTitle set the text to display on a menu item
func (item *MenuItem) SetTitle(title string) {
item.title = title
item.update()
}
// SetTooltip set the tooltip to show when mouse hover
func (item *MenuItem) SetTooltip(tooltip string) {
item.tooltip = tooltip
item.update()
}
// Disabled checks if the menu item is disabled
func (item *MenuItem) Disabled() bool {
return item.disabled
}
// Enable a menu item regardless if it's previously enabled or not
func (item *MenuItem) Enable() {
item.disabled = false
item.update()
}
// Disable a menu item regardless if it's previously disabled or not
func (item *MenuItem) Disable() {
item.disabled = true
item.update()
}
// Hide hides a menu item
func (item *MenuItem) Hide() {
hideMenuItem(item)
}
// Remove removes a menu item
func (item *MenuItem) Remove() {
menuItemsLock.RLock()
var childList []*MenuItem
for _, child := range menuItems {
if child.parent == item {
childList = append(childList, child)
}
}
menuItemsLock.RUnlock()
for _, child := range childList {
child.Remove()
}
removeMenuItem(item)
menuItemsLock.Lock()
delete(menuItems, item.id)
select {
case <-item.ClickedCh:
default:
}
close(item.ClickedCh)
menuItemsLock.Unlock()
}
// Show shows a previously hidden menu item
func (item *MenuItem) Show() {
showMenuItem(item)
}
// Checked returns if the menu item has a check mark
func (item *MenuItem) Checked() bool {
return item.checked
}
// Check a menu item regardless if it's previously checked or not
func (item *MenuItem) Check() {
item.checked = true
item.update()
}
// Uncheck a menu item regardless if it's previously unchecked or not
func (item *MenuItem) Uncheck() {
item.checked = false
item.update()
}
// update propagates changes on a menu item to systray
func (item *MenuItem) update() {
menuItemsLock.Lock()
menuItems[item.id] = item
menuItemsLock.Unlock()
addOrUpdateMenuItem(item)
}
func systrayMenuItemSelected(id uint32) {
menuItemsLock.RLock()
item, ok := menuItems[id]
menuItemsLock.RUnlock()
if !ok {
log.Printf("systray error: no menu item with ID %d\n", id)
return
}
select {
case item.ClickedCh <- struct{}{}:
// in case no one waiting for the channel
default:
}
}

26
vendor/fyne.io/systray/systray.h generated vendored Normal file
View File

@@ -0,0 +1,26 @@
#include "stdbool.h"
extern void systray_ready();
extern void systray_on_exit();
extern void systray_left_click();
extern void systray_right_click();
extern void systray_menu_item_selected(int menu_id);
extern void systray_menu_will_open();
void registerSystray(void);
void nativeEnd(void);
int nativeLoop(void);
void nativeStart(void);
void setIcon(const char* iconBytes, int length, bool template);
void setMenuItemIcon(const char* iconBytes, int length, int menuId, bool template);
void setTitle(char* title);
void setTooltip(char* tooltip);
void setRemovalAllowed(bool allowed);
void add_or_update_menu_item(int menuId, int parentMenuId, char* title, char* tooltip, short disabled, short checked, short isCheckable);
void add_separator(int menuId, int parentId);
void hide_menu_item(int menuId);
void remove_menu_item(int menuId);
void show_menu_item(int menuId);
void reset_menu();
void show_menu();
void quit();

213
vendor/fyne.io/systray/systray_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,213 @@
//go:build !ios
package systray
/*
#cgo darwin CFLAGS: -DDARWIN -x objective-c -fobjc-arc
#cgo darwin LDFLAGS: -framework Cocoa
#include <stdbool.h>
#include "systray.h"
void setInternalLoop(bool);
*/
import "C"
import (
"fmt"
"os"
"unsafe"
)
// SetTemplateIcon sets the systray icon as a template icon (on Mac), falling back
// to a regular icon on other platforms.
// templateIconBytes and regularIconBytes should be the content of .ico for windows and
// .ico/.jpg/.png for other platforms.
func SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte) {
cstr := (*C.char)(unsafe.Pointer(&templateIconBytes[0]))
C.setIcon(cstr, (C.int)(len(templateIconBytes)), true)
}
// SetIcon sets the icon of a menu item. Only works on macOS and Windows.
// iconBytes should be the content of .ico/.jpg/.png
func (item *MenuItem) SetIcon(iconBytes []byte) {
cstr := (*C.char)(unsafe.Pointer(&iconBytes[0]))
C.setMenuItemIcon(cstr, (C.int)(len(iconBytes)), C.int(item.id), false)
}
// SetIconFromFilePath sets the icon of a menu item from a file path.
// iconFilePath should be the path to a .ico for windows and .ico/.jpg/.png for other platforms.
func (item *MenuItem) SetIconFromFilePath(iconFilePath string) error {
iconBytes, err := os.ReadFile(iconFilePath)
if err != nil {
return fmt.Errorf("failed to read icon file: %v", err)
}
item.SetIcon(iconBytes)
return nil
}
// SetTemplateIcon sets the icon of a menu item as a template icon (on macOS). On Windows, it
// falls back to the regular icon bytes and on Linux it does nothing.
// templateIconBytes and regularIconBytes should be the content of .ico for windows and
// .ico/.jpg/.png for other platforms.
func (item *MenuItem) SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte) {
cstr := (*C.char)(unsafe.Pointer(&templateIconBytes[0]))
C.setMenuItemIcon(cstr, (C.int)(len(templateIconBytes)), C.int(item.id), true)
}
// SetRemovalAllowed sets whether a user can remove the systray icon or not.
// This is only supported on macOS.
func SetRemovalAllowed(allowed bool) {
C.setRemovalAllowed((C.bool)(allowed))
}
func registerSystray() {
C.registerSystray()
}
func nativeLoop() {
C.nativeLoop()
}
func nativeEnd() {
C.nativeEnd()
}
func nativeStart() {
C.nativeStart()
}
func quit() {
C.quit()
}
func setInternalLoop(internal bool) {
C.setInternalLoop(C.bool(internal))
}
// SetIcon sets the systray icon.
// iconBytes should be the content of .ico for windows and .ico/.jpg/.png
// for other platforms.
func SetIcon(iconBytes []byte) {
cstr := (*C.char)(unsafe.Pointer(&iconBytes[0]))
C.setIcon(cstr, (C.int)(len(iconBytes)), false)
}
// SetIconFromFilePath sets the systray icon from a file path.
// iconFilePath should be the path to a .ico for windows and .ico/.jpg/.png for other platforms.
func SetIconFromFilePath(iconFilePath string) error {
bytes, err := os.ReadFile(iconFilePath)
if err != nil {
return fmt.Errorf("failed to read icon file: %v", err)
}
SetIcon(bytes)
return nil
}
// SetTitle sets the systray title, only available on Mac and Linux.
func SetTitle(title string) {
C.setTitle(C.CString(title))
}
// SetTooltip sets the systray tooltip to display on mouse hover of the tray icon,
// only available on Mac and Windows.
func SetTooltip(tooltip string) {
C.setTooltip(C.CString(tooltip))
}
func addOrUpdateMenuItem(item *MenuItem) {
var disabled C.short
if item.disabled {
disabled = 1
}
var checked C.short
if item.checked {
checked = 1
}
var isCheckable C.short
if item.isCheckable {
isCheckable = 1
}
var parentID uint32 = 0
if item.parent != nil {
parentID = item.parent.id
}
C.add_or_update_menu_item(
C.int(item.id),
C.int(parentID),
C.CString(item.title),
C.CString(item.tooltip),
disabled,
checked,
isCheckable,
)
}
func addSeparator(id uint32, parent uint32) {
C.add_separator(C.int(id), C.int(parent))
}
func hideMenuItem(item *MenuItem) {
C.hide_menu_item(
C.int(item.id),
)
}
func showMenuItem(item *MenuItem) {
C.show_menu_item(
C.int(item.id),
)
}
func removeMenuItem(item *MenuItem) {
C.remove_menu_item(
C.int(item.id),
)
}
func resetMenu() {
C.reset_menu()
}
//export systray_left_click
func systray_left_click() {
if fn := tappedLeft; fn != nil {
fn()
return
}
C.show_menu()
}
//export systray_right_click
func systray_right_click() {
if fn := tappedRight; fn != nil {
fn()
return
}
C.show_menu()
}
//export systray_ready
func systray_ready() {
systrayReady()
}
//export systray_on_exit
func systray_on_exit() {
runSystrayExit()
}
//export systray_menu_item_selected
func systray_menu_item_selected(cID C.int) {
systrayMenuItemSelected(uint32(cID))
}
//export systray_menu_will_open
func systray_menu_will_open() {
select {
case TrayOpenedCh <- struct{}{}:
default:
}
}

464
vendor/fyne.io/systray/systray_darwin.m generated vendored Normal file
View File

@@ -0,0 +1,464 @@
//go:build !ios
#import <Cocoa/Cocoa.h>
#include "systray.h"
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101400
#ifndef NSControlStateValueOff
#define NSControlStateValueOff NSOffState
#endif
#ifndef NSControlStateValueOn
#define NSControlStateValueOn NSOnState
#endif
#endif
@interface MenuItem : NSObject
{
@public
NSNumber* menuId;
NSNumber* parentMenuId;
NSString* title;
NSString* tooltip;
short disabled;
short checked;
}
-(id) initWithId: (int)theMenuId
withParentMenuId: (int)theParentMenuId
withTitle: (const char*)theTitle
withTooltip: (const char*)theTooltip
withDisabled: (short)theDisabled
withChecked: (short)theChecked;
@end
@implementation MenuItem
-(id) initWithId: (int)theMenuId
withParentMenuId: (int)theParentMenuId
withTitle: (const char*)theTitle
withTooltip: (const char*)theTooltip
withDisabled: (short)theDisabled
withChecked: (short)theChecked
{
menuId = [NSNumber numberWithInt:theMenuId];
parentMenuId = [NSNumber numberWithInt:theParentMenuId];
title = [[NSString alloc] initWithCString:theTitle
encoding:NSUTF8StringEncoding];
tooltip = [[NSString alloc] initWithCString:theTooltip
encoding:NSUTF8StringEncoding];
disabled = theDisabled;
checked = theChecked;
return self;
}
@end
@interface RightClickDetector : NSView
@property (copy) void (^onRightClicked)(NSEvent *);
@end
@implementation RightClickDetector
- (void)rightMouseUp:(NSEvent *)theEvent {
if (!self.onRightClicked) {
return;
}
self.onRightClicked(theEvent);
}
@end
@interface SystrayAppDelegate: NSObject <NSApplicationDelegate, NSMenuDelegate>
- (void) add_or_update_menu_item:(MenuItem*) item;
- (IBAction)menuHandler:(id)sender;
- (void)menuWillOpen:(NSMenu*)menu;
@property (assign) IBOutlet NSWindow *window;
@end
@implementation SystrayAppDelegate
{
NSStatusItem *statusItem;
NSMenu *menu;
NSCondition* cond;
}
@synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
self->statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
self->menu = [[NSMenu alloc] init];
self->menu.delegate = self;
self->menu.autoenablesItems = FALSE;
// Once the user has removed it, the item needs to be explicitly brought back,
// even restarting the application is insufficient.
// Since the interface from Go is relatively simple, for now we ensure it's
// always visible at application startup.
self->statusItem.visible = TRUE;
NSStatusBarButton *button = self->statusItem.button;
button.action = @selector(leftMouseClicked);
[NSEvent addLocalMonitorForEventsMatchingMask: (NSEventTypeLeftMouseDown|NSEventTypeRightMouseDown)
handler: ^NSEvent *(NSEvent *event) {
if (event.window != self->statusItem.button.window) {
return event;
}
[self leftMouseClicked];
return nil;
}];
NSSize size = [button frame].size;
NSRect frame = CGRectMake(0, 0, size.width, size.height);
RightClickDetector *rightClicker = [[RightClickDetector alloc] initWithFrame:frame];
rightClicker.onRightClicked = ^(NSEvent *event) {
[self rightMouseClicked];
};
rightClicker.autoresizingMask = (NSViewWidthSizable |
NSViewHeightSizable);
button.autoresizesSubviews = YES;
[button addSubview:rightClicker];
systray_ready();
}
- (void)rightMouseClicked {
systray_right_click();
}
- (void)leftMouseClicked {
systray_left_click();
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
systray_on_exit();
}
- (void)setRemovalAllowed {
NSStatusItemBehavior behavior = [self->statusItem behavior];
behavior |= NSStatusItemBehaviorRemovalAllowed;
self->statusItem.behavior = behavior;
}
- (void)setRemovalForbidden {
NSStatusItemBehavior behavior = [self->statusItem behavior];
behavior &= ~NSStatusItemBehaviorRemovalAllowed;
// Ensure the menu item is visible if it was removed, since we're now
// disallowing removal.
self->statusItem.visible = TRUE;
self->statusItem.behavior = behavior;
}
- (void)setIcon:(NSImage *)image {
statusItem.button.image = image;
[self updateTitleButtonStyle];
}
- (void)setTitle:(NSString *)title {
statusItem.button.title = title;
[self updateTitleButtonStyle];
}
- (void)updateTitleButtonStyle {
if (statusItem.button.image != nil) {
if ([statusItem.button.title length] == 0) {
statusItem.button.imagePosition = NSImageOnly;
} else {
statusItem.button.imagePosition = NSImageLeft;
}
} else {
statusItem.button.imagePosition = NSNoImage;
}
}
- (void)setTooltip:(NSString *)tooltip {
statusItem.button.toolTip = tooltip;
}
- (IBAction)menuHandler:(id)sender
{
NSNumber* menuId = [sender representedObject];
systray_menu_item_selected(menuId.intValue);
}
- (void)menuWillOpen:(NSMenu *)menu {
systray_menu_will_open();
}
- (void)add_or_update_menu_item:(MenuItem *)item {
NSMenu *theMenu = self->menu;
NSMenuItem *parentItem;
if ([item->parentMenuId integerValue] > 0) {
parentItem = find_menu_item(menu, item->parentMenuId);
if (parentItem.hasSubmenu) {
theMenu = parentItem.submenu;
} else {
theMenu = [[NSMenu alloc] init];
[theMenu setAutoenablesItems:NO];
[parentItem setSubmenu:theMenu];
}
}
NSMenuItem *menuItem = find_menu_item(theMenu, item->menuId);
if (menuItem == NULL) {
menuItem = [theMenu addItemWithTitle:item->title
action:@selector(menuHandler:)
keyEquivalent:@""];
[menuItem setRepresentedObject:item->menuId];
}
[menuItem setTitle:item->title];
[menuItem setTag:[item->menuId integerValue]];
[menuItem setTarget:self];
[menuItem setToolTip:item->tooltip];
if (item->disabled == 1) {
menuItem.enabled = FALSE;
} else {
menuItem.enabled = TRUE;
}
if (item->checked == 1) {
menuItem.state = NSControlStateValueOn;
} else {
menuItem.state = NSControlStateValueOff;
}
}
NSMenuItem *find_menu_item(NSMenu *ourMenu, NSNumber *menuId) {
NSMenuItem *foundItem = [ourMenu itemWithTag:[menuId integerValue]];
if (foundItem != NULL) {
return foundItem;
}
NSArray *menu_items = ourMenu.itemArray;
int i;
for (i = 0; i < [menu_items count]; i++) {
NSMenuItem *i_item = [menu_items objectAtIndex:i];
if (i_item.hasSubmenu) {
foundItem = find_menu_item(i_item.submenu, menuId);
if (foundItem != NULL) {
return foundItem;
}
}
}
return NULL;
};
- (void) add_separator:(NSNumber*) parentMenuId
{
if (parentMenuId.integerValue != 0) {
NSMenuItem* menuItem = find_menu_item(menu, parentMenuId);
if (menuItem != NULL) {
[menuItem.submenu addItem: [NSMenuItem separatorItem]];
return;
}
}
[menu addItem: [NSMenuItem separatorItem]];
}
- (void) hide_menu_item:(NSNumber*) menuId
{
NSMenuItem* menuItem = find_menu_item(menu, menuId);
if (menuItem != NULL) {
[menuItem setHidden:TRUE];
}
}
- (void) setMenuItemIcon:(NSArray*)imageAndMenuId {
NSImage* image = [imageAndMenuId objectAtIndex:0];
NSNumber* menuId = [imageAndMenuId objectAtIndex:1];
NSMenuItem* menuItem;
menuItem = find_menu_item(menu, menuId);
if (menuItem == NULL) {
return;
}
menuItem.image = image;
}
- (void)show_menu
{
[self->menu popUpMenuPositioningItem:nil
atLocation:NSMakePoint(0, self->statusItem.button.bounds.size.height+6)
inView:self->statusItem.button];
}
- (void) show_menu_item:(NSNumber*) menuId
{
NSMenuItem* menuItem = find_menu_item(menu, menuId);
if (menuItem != NULL) {
[menuItem setHidden:FALSE];
}
}
- (void) remove_menu_item:(NSNumber*) menuId
{
NSMenuItem* menuItem = find_menu_item(menu, menuId);
if (menuItem != NULL) {
[menuItem.menu removeItem:menuItem];
}
}
- (void) reset_menu
{
[self->menu removeAllItems];
}
- (void) quit
{
// This tells the app event loop to stop after processing remaining messages.
[NSApp stop:self];
// The event loop won't return until it processes another event.
// https://stackoverflow.com/a/48064752/149482
NSPoint eventLocation = NSMakePoint(0, 0);
NSEvent *customEvent = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:eventLocation
modifierFlags:0
timestamp:0
windowNumber:0
context:nil
subtype:0
data1:0
data2:0];
[NSApp postEvent:customEvent atStart:NO];
}
@end
bool internalLoop = false;
SystrayAppDelegate *owner;
void setInternalLoop(bool i) {
internalLoop = i;
}
void registerSystray(void) {
if (!internalLoop) { // with an external loop we don't take ownership of the app
return;
}
owner = [[SystrayAppDelegate alloc] init];
[[NSApplication sharedApplication] setDelegate:owner];
// A workaround to avoid crashing on macOS versions before Catalina. Somehow
// SIGSEGV would happen inside AppKit if [NSApp run] is called from a
// different function, even if that function is called right after this.
if (floor(NSAppKitVersionNumber) <= /*NSAppKitVersionNumber10_14*/ 1671){
[NSApp run];
}
}
void nativeEnd(void) {
systray_on_exit();
}
int nativeLoop(void) {
if (floor(NSAppKitVersionNumber) > /*NSAppKitVersionNumber10_14*/ 1671){
[NSApp run];
}
return EXIT_SUCCESS;
}
void nativeStart(void) {
owner = [[SystrayAppDelegate alloc] init];
NSNotification *launched = [NSNotification notificationWithName:NSApplicationDidFinishLaunchingNotification
object:[NSApplication sharedApplication]];
[owner applicationDidFinishLaunching:launched];
}
void runInMainThread(SEL method, id object) {
[owner
performSelectorOnMainThread:method
withObject:object
waitUntilDone: YES];
}
void setIcon(const char* iconBytes, int length, bool template) {
NSData* buffer = [NSData dataWithBytes: iconBytes length:length];
@autoreleasepool {
NSImage *image = [[NSImage alloc] initWithData:buffer];
[image setSize:NSMakeSize(16, 16)];
image.template = template;
runInMainThread(@selector(setIcon:), (id)image);
}
}
void setMenuItemIcon(const char* iconBytes, int length, int menuId, bool template) {
NSData* buffer = [NSData dataWithBytes: iconBytes length:length];
@autoreleasepool {
NSImage *image = [[NSImage alloc] initWithData:buffer];
[image setSize:NSMakeSize(16, 16)];
image.template = template;
NSNumber *mId = [NSNumber numberWithInt:menuId];
runInMainThread(@selector(setMenuItemIcon:), @[image, (id)mId]);
}
}
void setTitle(char* ctitle) {
NSString* title = [[NSString alloc] initWithCString:ctitle
encoding:NSUTF8StringEncoding];
free(ctitle);
runInMainThread(@selector(setTitle:), (id)title);
}
void setTooltip(char* ctooltip) {
NSString* tooltip = [[NSString alloc] initWithCString:ctooltip
encoding:NSUTF8StringEncoding];
free(ctooltip);
runInMainThread(@selector(setTooltip:), (id)tooltip);
}
void setRemovalAllowed(bool allowed) {
if (allowed) {
runInMainThread(@selector(setRemovalAllowed), nil);
} else {
runInMainThread(@selector(setRemovalForbidden), nil);
}
}
void add_or_update_menu_item(int menuId, int parentMenuId, char* title, char* tooltip, short disabled, short checked, short isCheckable) {
MenuItem* item = [[MenuItem alloc] initWithId: menuId withParentMenuId: parentMenuId withTitle: title withTooltip: tooltip withDisabled: disabled withChecked: checked];
free(title);
free(tooltip);
runInMainThread(@selector(add_or_update_menu_item:), (id)item);
}
void add_separator(int menuId, int parentId) {
NSNumber *pId = [NSNumber numberWithInt:parentId];
runInMainThread(@selector(add_separator:), (id)pId);
}
void hide_menu_item(int menuId) {
NSNumber *mId = [NSNumber numberWithInt:menuId];
runInMainThread(@selector(hide_menu_item:), (id)mId);
}
void remove_menu_item(int menuId) {
NSNumber *mId = [NSNumber numberWithInt:menuId];
runInMainThread(@selector(remove_menu_item:), (id)mId);
}
void show_menu() {
runInMainThread(@selector(show_menu), nil);
}
void show_menu_item(int menuId) {
NSNumber *mId = [NSNumber numberWithInt:menuId];
runInMainThread(@selector(show_menu_item:), (id)mId);
}
void reset_menu() {
runInMainThread(@selector(reset_menu), nil);
}
void quit() {
runInMainThread(@selector(quit), nil);
}

370
vendor/fyne.io/systray/systray_menu_unix.go generated vendored Normal file
View File

@@ -0,0 +1,370 @@
//go:build (linux || freebsd || openbsd || netbsd) && !android
package systray
import (
"fmt"
"log"
"os"
"github.com/godbus/dbus/v5"
"github.com/godbus/dbus/v5/prop"
"fyne.io/systray/internal/generated/menu"
)
// SetIcon sets the icon of a menu item.
// iconBytes should be the content of .ico/.jpg/.png
func (item *MenuItem) SetIcon(iconBytes []byte) {
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
m, exists := findLayout(int32(item.id))
if exists {
m.V1["icon-data"] = dbus.MakeVariant(iconBytes)
refresh()
}
}
// SetIconFromFilePath sets the icon of a menu item from a file path.
// iconFilePath should be the path to a .ico for windows and .ico/.jpg/.png for other platforms.
func (item *MenuItem) SetIconFromFilePath(iconFilePath string) error {
iconBytes, err := os.ReadFile(iconFilePath)
if err != nil {
return fmt.Errorf("failed to read icon file: %v", err)
}
item.SetIcon(iconBytes)
return nil
}
// copyLayout makes full copy of layout
func copyLayout(in *menuLayout, depth int32) *menuLayout {
out := menuLayout{
V0: in.V0,
V1: make(map[string]dbus.Variant, len(in.V1)),
}
for k, v := range in.V1 {
out.V1[k] = v
}
if depth != 0 {
depth--
out.V2 = make([]dbus.Variant, len(in.V2))
for i, v := range in.V2 {
out.V2[i] = dbus.MakeVariant(copyLayout(v.Value().(*menuLayout), depth))
}
} else {
out.V2 = []dbus.Variant{}
}
return &out
}
// GetLayout is com.canonical.dbusmenu.GetLayout method.
func (t *tray) GetLayout(parentID int32, recursionDepth int32, propertyNames []string) (revision uint32, layout menuLayout, err *dbus.Error) {
initialMenuBuilt.Wait()
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
if m, ok := findLayout(parentID); ok {
// return copy of menu layout to prevent panic from cuncurrent access to layout
return instance.menuVersion, *copyLayout(m, recursionDepth), nil
}
return
}
// GetGroupProperties is com.canonical.dbusmenu.GetGroupProperties method.
func (t *tray) GetGroupProperties(ids []int32, propertyNames []string) (properties []struct {
V0 int32
V1 map[string]dbus.Variant
}, err *dbus.Error) {
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
for _, id := range ids {
if m, ok := findLayout(id); ok {
p := struct {
V0 int32
V1 map[string]dbus.Variant
}{
V0: m.V0,
V1: make(map[string]dbus.Variant, len(m.V1)),
}
for k, v := range m.V1 {
p.V1[k] = v
}
properties = append(properties, p)
}
}
return
}
// GetProperty is com.canonical.dbusmenu.GetProperty method.
func (t *tray) GetProperty(id int32, name string) (value dbus.Variant, err *dbus.Error) {
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
if m, ok := findLayout(id); ok {
if p, ok := m.V1[name]; ok {
return p, nil
}
}
return
}
// Event is com.canonical.dbusmenu.Event method.
func (t *tray) Event(id int32, eventID string, data dbus.Variant, timestamp uint32) (err *dbus.Error) {
switch eventID {
case "clicked":
systrayMenuItemSelected(uint32(id))
case "opened":
t.menuLock.RLock()
rootMenuID := t.menu.V0
t.menuLock.RUnlock()
if id == rootMenuID {
select {
case TrayOpenedCh <- struct{}{}:
default:
}
}
}
return
}
// EventGroup is com.canonical.dbusmenu.EventGroup method.
func (t *tray) EventGroup(events []struct {
V0 int32
V1 string
V2 dbus.Variant
V3 uint32
}) (idErrors []int32, err *dbus.Error) {
for _, event := range events {
if event.V1 == "clicked" {
systrayMenuItemSelected(uint32(event.V0))
}
}
return
}
// AboutToShow is com.canonical.dbusmenu.AboutToShow method.
func (t *tray) AboutToShow(id int32) (needUpdate bool, err *dbus.Error) {
return
}
// AboutToShowGroup is com.canonical.dbusmenu.AboutToShowGroup method.
func (t *tray) AboutToShowGroup(ids []int32) (updatesNeeded []int32, idErrors []int32, err *dbus.Error) {
return
}
func createMenuPropSpec() map[string]map[string]*prop.Prop {
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
return map[string]map[string]*prop.Prop{
"com.canonical.dbusmenu": {
"Version": {
Value: instance.menuVersion,
Writable: true,
Emit: prop.EmitTrue,
Callback: nil,
},
"TextDirection": {
Value: "ltr",
Writable: false,
Emit: prop.EmitTrue,
Callback: nil,
},
"Status": {
Value: "normal",
Writable: false,
Emit: prop.EmitTrue,
Callback: nil,
},
"IconThemePath": {
Value: []string{},
Writable: false,
Emit: prop.EmitTrue,
Callback: nil,
},
},
}
}
// menuLayout is a named struct to map into generated bindings. It represents the layout of a menu item
type menuLayout = struct {
V0 int32 // the unique ID of this item
V1 map[string]dbus.Variant // properties for this menu item layout
V2 []dbus.Variant // child menu item layouts
}
func addOrUpdateMenuItem(item *MenuItem) {
var layout *menuLayout
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
m, exists := findLayout(int32(item.id))
if exists {
layout = m
} else {
layout = &menuLayout{
V0: int32(item.id),
V1: map[string]dbus.Variant{},
V2: []dbus.Variant{},
}
parent := instance.menu
if item.parent != nil {
m, ok := findLayout(int32(item.parent.id))
if ok {
parent = m
parent.V1["children-display"] = dbus.MakeVariant("submenu")
}
}
parent.V2 = append(parent.V2, dbus.MakeVariant(layout))
}
applyItemToLayout(item, layout)
if exists {
refresh()
}
}
func addSeparator(id uint32, parent uint32) {
menu, _ := findLayout(int32(parent))
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
layout := &menuLayout{
V0: int32(id),
V1: map[string]dbus.Variant{
"type": dbus.MakeVariant("separator"),
},
V2: []dbus.Variant{},
}
menu.V2 = append(menu.V2, dbus.MakeVariant(layout))
refresh()
}
func applyItemToLayout(in *MenuItem, out *menuLayout) {
out.V1["enabled"] = dbus.MakeVariant(!in.disabled)
out.V1["label"] = dbus.MakeVariant(in.title)
if in.isCheckable {
out.V1["toggle-type"] = dbus.MakeVariant("checkmark")
if in.checked {
out.V1["toggle-state"] = dbus.MakeVariant(1)
} else {
out.V1["toggle-state"] = dbus.MakeVariant(0)
}
} else {
out.V1["toggle-type"] = dbus.MakeVariant("")
out.V1["toggle-state"] = dbus.MakeVariant(0)
}
}
func findLayout(id int32) (*menuLayout, bool) {
if id == 0 {
return instance.menu, true
}
return findSubLayout(id, instance.menu.V2)
}
func findSubLayout(id int32, vals []dbus.Variant) (*menuLayout, bool) {
for _, i := range vals {
item := i.Value().(*menuLayout)
if item.V0 == id {
return item, true
}
if len(item.V2) > 0 {
child, ok := findSubLayout(id, item.V2)
if ok {
return child, true
}
}
}
return nil, false
}
func removeSubLayout(id int32, vals []dbus.Variant) ([]dbus.Variant, bool) {
for idx, i := range vals {
item := i.Value().(*menuLayout)
if item.V0 == id {
return append(vals[:idx], vals[idx+1:]...), true
}
if len(item.V2) > 0 {
if child, removed := removeSubLayout(id, item.V2); removed {
return child, true
}
}
}
return vals, false
}
func removeMenuItem(item *MenuItem) {
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
parent := instance.menu
if item.parent != nil {
m, ok := findLayout(int32(item.parent.id))
if !ok {
return
}
parent = m
}
if items, removed := removeSubLayout(int32(item.id), parent.V2); removed {
parent.V2 = items
refresh()
}
}
func hideMenuItem(item *MenuItem) {
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
m, exists := findLayout(int32(item.id))
if exists {
m.V1["visible"] = dbus.MakeVariant(false)
refresh()
}
}
func showMenuItem(item *MenuItem) {
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
m, exists := findLayout(int32(item.id))
if exists {
m.V1["visible"] = dbus.MakeVariant(true)
refresh()
}
}
func refresh() {
instance.lock.Lock()
defer instance.lock.Unlock()
if instance.conn == nil || instance.menuProps == nil {
return
}
instance.menuVersion++
dbusErr := instance.menuProps.Set("com.canonical.dbusmenu", "Version",
dbus.MakeVariant(instance.menuVersion))
if dbusErr != nil {
log.Printf("systray error: failed to update menu version: %v\n", dbusErr)
return
}
err := menu.Emit(instance.conn, &menu.Dbusmenu_LayoutUpdatedSignal{
Path: menuPath,
Body: &menu.Dbusmenu_LayoutUpdatedSignalBody{
Revision: instance.menuVersion,
},
})
if err != nil {
log.Printf("systray error: failed to emit layout updated signal: %v\n", err)
}
}
func resetMenu() {
instance.menuLock.Lock()
defer instance.menuLock.Unlock()
instance.menu = &menuLayout{}
instance.menuVersion++
refresh()
}

44
vendor/fyne.io/systray/systray_notifier_unix.go generated vendored Normal file
View File

@@ -0,0 +1,44 @@
package systray
import (
"fyne.io/systray/internal/generated/notifier"
"github.com/godbus/dbus/v5"
)
type leftRightNotifierItem struct {
}
func newLeftRightNotifierItem() notifier.StatusNotifierItemer {
return &leftRightNotifierItem{}
}
func (i *leftRightNotifierItem) Activate(_, _ int32) *dbus.Error {
if f := tappedLeft; f == nil {
return &dbus.ErrMsgUnknownMethod
}
tappedLeft()
return nil
}
func (i *leftRightNotifierItem) ContextMenu(_, _ int32) *dbus.Error {
if f := tappedRight; f == nil {
return &dbus.ErrMsgUnknownMethod
}
tappedRight()
return nil
}
func (i *leftRightNotifierItem) SecondaryActivate(_, _ int32) *dbus.Error {
if f := tappedRight; f == nil {
return &dbus.ErrMsgUnknownMethod
}
tappedRight()
return nil
}
func (i *leftRightNotifierItem) Scroll(_ int32, _ string) *dbus.Error {
return &dbus.ErrMsgUnknownMethod
}

435
vendor/fyne.io/systray/systray_unix.go generated vendored Normal file
View File

@@ -0,0 +1,435 @@
//go:build (linux || freebsd || openbsd || netbsd) && !android
//Note that you need to have github.com/knightpp/dbus-codegen-go installed from "custom" branch
//go:generate dbus-codegen-go -prefix org.kde -package notifier -output internal/generated/notifier/status_notifier_item.go internal/StatusNotifierItem.xml
//go:generate dbus-codegen-go -prefix com.canonical -package menu -output internal/generated/menu/dbus_menu.go internal/DbusMenu.xml
package systray
import (
"bytes"
"fmt"
"image"
_ "image/png" // used only here
"log"
"os"
"sync"
"github.com/godbus/dbus/v5"
"github.com/godbus/dbus/v5/introspect"
"github.com/godbus/dbus/v5/prop"
"fyne.io/systray/internal/generated/menu"
"fyne.io/systray/internal/generated/notifier"
)
const (
path = "/StatusNotifierItem"
menuPath = "/StatusNotifierItem/menu"
)
var (
// to signal quitting the internal main loop
quitChan = make(chan struct{})
// instance is the current instance of our DBus tray server
instance = &tray{menu: &menuLayout{}, menuVersion: 1}
)
// SetTemplateIcon sets the systray icon as a template icon (on macOS), falling back
// to a regular icon on other platforms.
// templateIconBytes and iconBytes should be the content of .ico for windows and
// .ico/.jpg/.png for other platforms.
func SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte) {
// TODO handle the templateIconBytes?
SetIcon(regularIconBytes)
}
// SetIcon sets the systray icon.
// iconBytes should be the content of .ico for windows and .ico/.jpg/.png
// for other platforms.
func SetIcon(iconBytes []byte) {
instance.lock.Lock()
instance.iconData = iconBytes
props := instance.props
conn := instance.conn
defer instance.lock.Unlock()
if props == nil {
return
}
props.SetMust("org.kde.StatusNotifierItem", "IconPixmap",
[]PX{convertToPixels(iconBytes)})
if conn == nil {
return
}
err := notifier.Emit(conn, &notifier.StatusNotifierItem_NewIconSignal{
Path: path,
Body: &notifier.StatusNotifierItem_NewIconSignalBody{},
})
if err != nil {
log.Printf("systray error: failed to emit new icon signal: %s\n", err)
return
}
}
// SetIconFromFilePath sets the systray icon from a file path.
// iconFilePath should be the path to a .ico for windows and .ico/.jpg/.png for other platforms.
func SetIconFromFilePath(iconFilePath string) error {
bytes, err := os.ReadFile(iconFilePath)
if err != nil {
return fmt.Errorf("failed to read icon file: %v", err)
}
SetIcon(bytes)
return nil
}
// SetTitle sets the systray title, only available on Mac and Linux.
func SetTitle(t string) {
instance.lock.Lock()
instance.title = t
props := instance.props
conn := instance.conn
defer instance.lock.Unlock()
if props == nil {
return
}
dbusErr := props.Set("org.kde.StatusNotifierItem", "Title",
dbus.MakeVariant(t))
if dbusErr != nil {
log.Printf("systray error: failed to set Title prop: %s\n", dbusErr)
return
}
if conn == nil {
return
}
err := notifier.Emit(conn, &notifier.StatusNotifierItem_NewTitleSignal{
Path: path,
Body: &notifier.StatusNotifierItem_NewTitleSignalBody{},
})
if err != nil {
log.Printf("systray error: failed to emit new title signal: %s\n", err)
return
}
}
// SetTooltip sets the systray tooltip to display on mouse hover of the tray icon,
// only available on Mac and Windows.
func SetTooltip(tooltipTitle string) {
instance.lock.Lock()
instance.tooltipTitle = tooltipTitle
props := instance.props
defer instance.lock.Unlock()
if props == nil {
return
}
dbusErr := props.Set("org.kde.StatusNotifierItem", "ToolTip",
dbus.MakeVariant(tooltip{V2: tooltipTitle}))
if dbusErr != nil {
log.Printf("systray error: failed to set ToolTip prop: %s\n", dbusErr)
return
}
}
// SetTemplateIcon sets the icon of a menu item as a template icon (on macOS). On Windows and
// Linux, it falls back to the regular icon bytes.
// templateIconBytes and regularIconBytes should be the content of .ico for windows and
// .ico/.jpg/.png for other platforms.
func (item *MenuItem) SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte) {
item.SetIcon(regularIconBytes)
}
// SetRemovalAllowed sets whether a user can remove the systray icon or not.
// This is only supported on macOS.
func SetRemovalAllowed(allowed bool) {
}
func setInternalLoop(_ bool) {
// nothing to action on Linux
}
func registerSystray() {
}
func nativeLoop() int {
nativeStart()
<-quitChan
nativeEnd()
return 0
}
func nativeEnd() {
runSystrayExit()
instance.conn.Close()
}
func quit() {
close(quitChan)
}
func nativeStart() {
systrayReady()
conn, err := dbus.SessionBus()
if err != nil {
log.Printf("systray error: failed to connect to DBus: %v\n", err)
return
}
err = notifier.ExportStatusNotifierItem(conn, path, newLeftRightNotifierItem())
if err != nil {
log.Printf("systray error: failed to export status notifier item: %v\n", err)
}
err = menu.ExportDbusmenu(conn, menuPath, instance)
if err != nil {
log.Printf("systray error: failed to export status notifier menu: %v\n", err)
return
}
name := fmt.Sprintf("org.kde.StatusNotifierItem-%d-1", os.Getpid()) // register id 1 for this process
_, err = conn.RequestName(name, dbus.NameFlagDoNotQueue)
if err != nil {
log.Printf("systray error: failed to request name: %s\n", err)
// it's not critical error: continue
}
props, err := prop.Export(conn, path, instance.createPropSpec())
if err != nil {
log.Printf("systray error: failed to export notifier item properties to bus: %s\n", err)
return
}
menuProps, err := prop.Export(conn, menuPath, createMenuPropSpec())
if err != nil {
log.Printf("systray error: failed to export notifier menu properties to bus: %s\n", err)
return
}
node := introspect.Node{
Name: path,
Interfaces: []introspect.Interface{
introspect.IntrospectData,
prop.IntrospectData,
notifier.IntrospectDataStatusNotifierItem,
},
}
err = conn.Export(introspect.NewIntrospectable(&node), path,
"org.freedesktop.DBus.Introspectable")
if err != nil {
log.Printf("systray error: failed to export node introspection: %s\n", err)
return
}
menuNode := introspect.Node{
Name: menuPath,
Interfaces: []introspect.Interface{
introspect.IntrospectData,
prop.IntrospectData,
menu.IntrospectDataDbusmenu,
},
}
err = conn.Export(introspect.NewIntrospectable(&menuNode), menuPath,
"org.freedesktop.DBus.Introspectable")
if err != nil {
log.Printf("systray error: failed to export menu node introspection: %s\n", err)
return
}
instance.lock.Lock()
instance.conn = conn
instance.props = props
instance.menuProps = menuProps
instance.lock.Unlock()
go stayRegistered()
}
func register() bool {
obj := instance.conn.Object("org.kde.StatusNotifierWatcher", "/StatusNotifierWatcher")
call := obj.Call("org.kde.StatusNotifierWatcher.RegisterStatusNotifierItem", 0, path)
if call.Err != nil {
log.Printf("systray error: failed to register: %v\n", call.Err)
return false
}
return true
}
func stayRegistered() {
register()
conn := instance.conn
if err := conn.AddMatchSignal(
dbus.WithMatchObjectPath("/org/freedesktop/DBus"),
dbus.WithMatchInterface("org.freedesktop.DBus"),
dbus.WithMatchSender("org.freedesktop.DBus"),
dbus.WithMatchMember("NameOwnerChanged"),
dbus.WithMatchArg(0, "org.kde.StatusNotifierWatcher"),
); err != nil {
log.Printf("systray error: failed to register signal matching: %v\n", err)
// If we can't monitor signals, there is no point in
// us being here. we're either registered or not (per
// above) and will roll the dice from here...
return
}
sc := make(chan *dbus.Signal, 10)
conn.Signal(sc)
for {
select {
case sig := <-sc:
if sig == nil {
return // We get a nil signal when closing the window.
} else if len(sig.Body) < 3 {
return // malformed signal?
}
// sig.Body has the args, which are [name old_owner new_owner]
if s, ok := sig.Body[2].(string); ok && s != "" {
register()
}
case <-quitChan:
return
}
}
}
// tray is a basic type that handles the dbus functionality
type tray struct {
// the DBus connection that we will use
conn *dbus.Conn
// icon data for the main systray icon
iconData []byte
// title and tooltip state
title, tooltipTitle string
lock sync.Mutex
menu *menuLayout
menuLock sync.RWMutex
props, menuProps *prop.Properties
menuVersion uint32
}
func (t *tray) createPropSpec() map[string]map[string]*prop.Prop {
t.lock.Lock()
defer t.lock.Unlock()
id := t.title
if id == "" {
id = fmt.Sprintf("systray_%d", os.Getpid())
}
return map[string]map[string]*prop.Prop{
"org.kde.StatusNotifierItem": {
"Status": {
Value: "Active", // Passive, Active or NeedsAttention
Writable: false,
Emit: prop.EmitTrue,
Callback: nil,
},
"Title": {
Value: t.title,
Writable: true,
Emit: prop.EmitTrue,
Callback: nil,
},
"Id": {
Value: id,
Writable: false,
Emit: prop.EmitTrue,
Callback: nil,
},
"Category": {
Value: "ApplicationStatus",
Writable: false,
Emit: prop.EmitTrue,
Callback: nil,
},
"IconName": {
Value: "",
Writable: false,
Emit: prop.EmitTrue,
Callback: nil,
},
"IconPixmap": {
Value: []PX{convertToPixels(t.iconData)},
Writable: true,
Emit: prop.EmitTrue,
Callback: nil,
},
"IconThemePath": {
Value: "",
Writable: false,
Emit: prop.EmitTrue,
Callback: nil,
},
"ItemIsMenu": {
Value: tappedLeft == nil && tappedRight == nil,
Writable: false,
Emit: prop.EmitTrue,
Callback: nil,
},
"Menu": {
Value: dbus.ObjectPath(menuPath),
Writable: true,
Emit: prop.EmitTrue,
Callback: nil,
},
"ToolTip": {
Value: tooltip{V2: t.tooltipTitle},
Writable: true,
Emit: prop.EmitTrue,
Callback: nil,
},
}}
}
// PX is picture pix map structure with width and high
type PX struct {
W, H int
Pix []byte
}
// tooltip is our data for a tooltip property.
// Param names need to match the generated code...
type tooltip = struct {
V0 string // name
V1 []PX // icons
V2 string // title
V3 string // description
}
func convertToPixels(data []byte) PX {
if len(data) == 0 {
return PX{}
}
img, _, err := image.Decode(bytes.NewReader(data))
if err != nil {
log.Printf("Failed to read icon format %v", err)
return PX{}
}
return PX{
img.Bounds().Dx(), img.Bounds().Dy(),
argbForImage(img),
}
}
func argbForImage(img image.Image) []byte {
w, h := img.Bounds().Dx(), img.Bounds().Dy()
data := make([]byte, w*h*4)
i := 0
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
r, g, b, a := img.At(x, y).RGBA()
data[i] = byte(a)
data[i+1] = byte(r)
data[i+2] = byte(g)
data[i+3] = byte(b)
i += 4
}
}
return data
}

1147
vendor/fyne.io/systray/systray_windows.go generated vendored Normal file

File diff suppressed because it is too large Load Diff