mirror of
https://github.com/nkanaev/yarr.git
synced 2026-05-03 07:47:42 +00:00
switch to fyne.io/systray
This commit is contained in:
13
vendor/fyne.io/systray/.gitignore
generated
vendored
Normal file
13
vendor/fyne.io/systray/.gitignore
generated
vendored
Normal 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
125
vendor/fyne.io/systray/CHANGELOG.md
generated
vendored
Normal 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
202
vendor/fyne.io/systray/LICENSE
generated
vendored
Normal 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
18
vendor/fyne.io/systray/Makefile
generated
vendored
Normal 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
147
vendor/fyne.io/systray/README.md
generated
vendored
Normal 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!
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
484
vendor/fyne.io/systray/internal/generated/menu/dbus_menu.go
generated
vendored
Normal file
484
vendor/fyne.io/systray/internal/generated/menu/dbus_menu.go
generated
vendored
Normal 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
|
||||
}
|
||||
633
vendor/fyne.io/systray/internal/generated/notifier/status_notifier_item.go
generated
vendored
Normal file
633
vendor/fyne.io/systray/internal/generated/notifier/status_notifier_item.go
generated
vendored
Normal 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
311
vendor/fyne.io/systray/systray.go
generated
vendored
Normal 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
26
vendor/fyne.io/systray/systray.h
generated
vendored
Normal 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
213
vendor/fyne.io/systray/systray_darwin.go
generated
vendored
Normal 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
464
vendor/fyne.io/systray/systray_darwin.m
generated
vendored
Normal 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
370
vendor/fyne.io/systray/systray_menu_unix.go
generated
vendored
Normal 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
44
vendor/fyne.io/systray/systray_notifier_unix.go
generated
vendored
Normal 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
435
vendor/fyne.io/systray/systray_unix.go
generated
vendored
Normal 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, ¬ifier.StatusNotifierItem_NewIconSignal{
|
||||
Path: path,
|
||||
Body: ¬ifier.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, ¬ifier.StatusNotifierItem_NewTitleSignal{
|
||||
Path: path,
|
||||
Body: ¬ifier.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
1147
vendor/fyne.io/systray/systray_windows.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user