Create a Custom System Tray Indicator For Your Tasks on Linux
Last Updated on January 7, 2020
System Tray icons are still considered to be an amazing functionality today. By just right-clicking on the icon, and then selecting which actions you would like to take, you may ease your life a lot and save many unnecessary clicks on daily basis.
When talking about useful system tray icons, examples like Skype, Dropbox and VLC do come to mind:
However, system tray icons can actually be quite a lot more useful; By simply building one yourself for your own needs. In this tutorial, we’ll explain how to do that for you in very simple steps.
Table of Contents
Prerequisites
We are going to build a custom system tray indicator using Python. Python is probably installed by default on all the major Linux distributions, so just check it’s there (version 2.7). Additionally, we’ll need the gir1.2-appindicator3 package installed. It’s the library allowing us to easily create system tray indicators.
To install it on Ubuntu/Mint/Debian:
For other distributions, just search for any packages containing appindicator .
Warning: On GNOME Shell, system tray icons are removed starting from 3.26. You’ll need to install the following extension (Or possibly other extensions) to re-enable the feature on your desktop. Otherwise, you won’t be able to see the indicator we are going to create here.
Basic Code
Here’s the basic code of the indicator:
We’ll explain how the code works later. But for know, just save it in a text file under the name tray.py , and run it using Python:
You’ll see the indicator working as follows:
Now, to explain how we did the magic:
- The first 3 lines of the code are nothing more than just specifying the Python path and importing the libraries we are going to use in our indicator.
- def main() : This is the main function of the indicator. Under it we write the code to initialize and build the indicator.
- indicator = appindicator.Indicator.new(“customtray”, “semi-starred-symbolic”, appindicator.IndicatorCategory.APPLICATION_STATUS) : Here we are specially creating a new indicator and calling it customtray . This is the special name of the indicator so that the system doesn’t mix it with other indicators that may be running. Also, we used the semi-starred-symbolic icon name as the default icon for our indicator. You could possibly change thing to any other things; Say firefox (if you want to see Firefox icon being used for the indicator), or any other icon name you would like. The last part regarding the APPLICATION_STATUS is just ordinary code for the categorization/scope of that indicator.
- indicator.set_status(appindicator.IndicatorStatus.ACTIVE) : This line just turns the indicator on.
- indicator.set_menu(menu()) : Here, we are saying that we want to use the menu() function (which we’ll define later) for creating the menu items of our indicator. This is important so that when you click on the indicator, you can see a list of possible actions to take.
- gtk.main() : Just run the main GTK loop.
- Under menu() you’ll see that we are creating the actions/items we want to provide using our indicator. command_one = gtk.MenuItem(‘My Notes’) simply initializes the first menu item with the text “My notes”, and then command_one.connect(‘activate’, note) connects the activate signal of that menu item to the note() function defined later; In other words, we are telling our system here: “When this menu item is clicked, run the note() function”. Finally, menu.append(command_one) adds that menu item to the list.
- The lines regarding exittray are just for creating an exit menu item to close the indicator any time you want.
- menu.show_all() and return menu are just ordinary codes for returning the menu list to the indicator.
- Under note(_) you’ll see the code that must be executed when the “My Notes” menu item is clicked. Here, we just wrote os.system(“gedit $HOME/Documents/notes.txt”) ; The os.system function is a function that allows us to run shell commands from inside Python, so here we wrote a command to open a file called notes.txt under the Documents folder in our home directory using the gedit editor. This for example can be your daily notes taking program from now on!
Adding your Needed Tasks
There are only 2 things you need to touch in the code:
- Define a new menu item under menu() for your desired task.
- Create a new function to run a specific action when that menu item is clicked.
So, let’s say that you want to create a new menu item, which when clicked, plays a specific video/audio file on your hard disk using VLC? To do it, simply add the following 3 lines in line 17:
And the following lines in line 30:
Replace /home/ /Videos/somevideo.mp4 with the path to the video/audio file you want. Now save the file and run the indicator again:
This is how you’ll see it now:
And when you click on the newly-created menu item, VLC will start playing!
To create other items/tasks, simply redo the steps again. Just be careful to replace command_two with another name, like command_three , so that no clash between variables happen. And then define new separate functions like what we did with the play(_) function.
The possibilities are endless from here; I am using this way for example to fetch some data from the web (using the urllib2 library) and display them for me any time. I am also using it for playing an mp3 file in the background using the mpg123 command, and I am defining another menu item to killall mpg123 to stop playing that audio whenever I want. CS:GO on Steam for example takes a huge time to exit (the window doesn’t close automatically), so as a workaround for this, I simply minimize the window and click on a menu item that I created which will execute killall -9 csgo_linux64 .
You can use this indicator for anything: Updating your system packages, possibly running some other scripts any time you want.. Literally anything.
Autostart on Boot
We want our system tray indicator to start automatically on boot, we don’t want to run it manually each time. To do that, simply add the following command to your startup applications (after you replace the path to the tray.py file with yours):
The very next time you reboot your system, the indicator will start working automatically after boot!
Conclusion
You now know how to create your own system tray indicator for any task that you may want. This method should save you a lot of time depending on the nature and number of tasks you need to run on daily basis. Some users may prefer creating aliases from the command line, but this will require you to always open the terminal window or have a drop-down terminal emulator available, while here, the system tray indicator is always working and available for you.
Have you used this method to run your tasks before? Would love to hear your thoughts.
Источник
System tray in linux
Professional, cross-platform SystemTray support for Swing/AWT, GtkStatusIcon, and AppIndicator on Java 6+.
This library provides OS Native menus and Swing/AWT menus, depending on the OS and Desktop Environment and if AutoDetect (the default) is enabled.
Linux/Unix will automatically choose Native (GtkStatusIcon or AppIndicator) menus, Windows will choose Native (WindowsNotifyIcon with Swing menus), and MacOS will choose AWT.
Please note that the Native and AWT menus follow the specified look and feel of that OS and are limited by what is supported on the OS. Consequently they are not consistent across all platforms and environments.
In most cases on Linux/Unix, Native menus are used. In cases where libraries are missing or there are un-resolvable GTK version conflicts, we try to fallback to using Swing.
The following unique problems are also solved by this library:
- Sun/Oracle system-tray icons on Linux/Unix do not support images with transparent backgrounds
- Sun/Oracle system-tray and SWT system-tray implementations do not support app-indicators, which are necessary on different distributions of Linux/Unix
- GNOME3 desktop environments hide or remove entirely system tray icons (hidden from 3.16-3.25, removed from 3.26+)
- Sun/Oracle system-tray menus on Windows look absolutely horrid
- Sun/Oracle system-tray icons on Windows are hard-coded to a max size of 24×24 (it was last updated in 2006)
- Sun/Oracle system-tray menus on MacOS do not always respond to both mouse buttons, where Apple menus do
- Windows native menus do not support images attached to menu entries
- Windows menus do not support a different L&F from the running application
- Windows, Linux, and MacOSX menus (native or otherwise) do not support HiDPI configurations
- java.awt.Desktop.getDesktop() is broken when using GTK3 or on MacOS.
This is for cross-platform use, specifically — linux 32/64, mac 32/64, and windows 32/64. Java 6+
Problems and Restrictions
JavaFX uses GTK2 for Java SystemTray.FORCE_GTK2=true; , or to change JavaFX (9+), use -Djdk.gtk.version=3 to solve this.
SWT can use GTK2, GTK3, or GTK4. We do not support GTK4, and recommend GTK3 (now the default for SWT) If you want to use something else, you must configure both SWT and the SystemTray to same, before SWT is initialized and only if there are problems with the autodetection, via SystemTray.FORCE_GTK2=true; .
AppIndicators under Ubuntu 16.04 (and possibly other distro’s) will not work as a different user without extra work (ie: as a sudo’d user to root ), since AppIndicators require a dbus connection to the current user’s window manager. (see the Notes below for the details)
MacOSX is a special snowflake in how it handles GUI events, and so there are some bizzaro combinations of SWT, JavaFX, and Swing that do not work together. (see the Notes below for the details)
MacOSX original menus cannot display images attached to menu entries. The native implementation supports images. If forced to Swing instead, the tray-menu will no longer support the OS theme and transparancy.
Gnome 3: 3.16 — 3.25 (Fedora, Manjaro, Arch, etc) environments by default do not allow the SystemTray icon to be shown. This has been worked around and the tray icon will be placed next to the clock. A different workaround is to install the [Top Icons] (https://extensions.gnome.org/extension/1031/topicons/) plugin which moves icons from the notification drawer sometimes at the bottom left (collapsed) corner of the screen to the menu panel next to the clock.
Gnome 3: 3.26+ (Fedora, Manjaro, Arch, etc) environments by default do not allow the SystemTray icon to be shown. This has been worked around and the tray icon will be placed next to the clock. A different workaround is to install the Appindicator Support plugin which allows the addition of app-indicator icons where one would expect. Additionally, you will need to install libappindicator-gtk3 .
ToolTips The maximum length is 64 characters long, and it is not supported on all Operating Systems and Desktop Environments. Specifically, Swing and GtkStatusIcon types support tray tooltips and menu tooltips. AWT and AppIndicator types do not support tooltips of any kind. Please note that Ubuntu uses AppIndicators!
Linux/Unix Menus Some Linux environments only support right-click to display the menu, and it is not possible to change the behavior.
Linux/Unix and java.awt.Desktop.getDesktop() Please use the dorkbox.util.Desktop class as a replacement, which will intelligently call the correct OS API to open a folder/directory, email, or browser. (Many thanks to QZ Tray for this).
WSL Windows Subsystem for Linux requires some extra work to get a tray icon showing correctly, either by starting java under windows (instead of WSL), or by adding an X-Server.
AutoDetect Compatibility List
OS | Supported |
---|---|
Arch Linux + Gnome3 | ✓ |
Manjaro Linux + KDE | ✓ |
ChromeOS | x |
Debian 8.5 + Gnome3 | ✓ |
Debian 8.6 + Gnome3 | ✓ |
Debian 9.5 + Gnome3 | ✓ |
Debian 9.5 + KDE | ✓ |
Debian 9.5 + Cinnamon | ✓ |
Debian 9.5 + MATE | ✓ |
Debian 9.5 + LXDE | ✓ |
Debian 9.5 + XFCE | ✓ |
Elementary OS 0.3.2 | ✓ |
Elementary OS 0.4 | ✓ |
Elementary OS 5.0 | * |
Fedora 23 | ✓ |
Fedora 24 | ✓ |
Fedora 25 | ✓ |
Fedora 25 KDE | ✓ |
Fedora 26 | ✓ |
Fedora 27 | ✓ |
Fedora 28 | ✓ |
Fedora 29 | ✓ |
FreeBSD 11 + Gnome3 | ✓ |
IGEL OS 9.5 | ✓ |
Kali 2016 | ✓ |
Kali 2017 | ✓ |
LinuxMint 18 | ✓ |
LinuxMint 19 | ✓ |
LinuxMint 20 | ✓ |
Ubuntu 12.04 | ✓ |
Ubuntu 14.04 | ✓ |
Ubuntu 16.04 | ✓ |
Ubuntu 17.04 | ✓ |
Ubuntu 17.10 | ✓ |
Ubuntu 18.04 | ✓ |
UbuntuGnome 16.04 | ✓ |
UbuntuGnome 17.04 | ✓ |
XUbuntu 16.04 | ✓ |
MacOSx | ✓ |
Windows XP | ✓ |
Windows 7 | ✓ |
Windows 8.1 | ✓ |
Windows 10 | ✓ |
WSL 1 | x |
WSL 2 | x |
If you have us working on an unlisted OS/DE, please let us know!!
The compatibility list only applies while the SystemTray is in AutoDetect mode. Not all OSes support forcing a custom tray type.
Some Linux operating systems with GNOME 3 might require the installation of the app-indicator library as well. We usually provide feedback when this is necessary. (Arch, Fedora, etc)
The menu item callbacks occur on their own dispatch thread (instead of being on whatever OS’s event dispatch thread), in order to provide consistent actions across all platforms. It is critical to make sure that access to Swing/etc that depend on running events inside their own EDT , are properly called. IE: SwingUtilities.invokeLater() . Do not use invokeAndWait() as weird GUI anomalies can happen.
Ubuntu 16.04+ with JavaFX require libappindicator1 because of JavaFX GTK and indicator panel incompatibilities. See more details. We attempt to fallback to using Swing in this situation.
Ubuntu 17.04 , Java only supports the X11 backend. MIR is not supported.
Debian + GNOME 3 , SystemTray works, but will only show in a tray via pressing SUPER+M.
MacOSX JavaFX (Java7) is incompatible with the SystemTray by default. See issue details.
- To fix this do one of the following
- Upgrade to Java 8
- Add : -Djavafx.macosx.embedded=true as a JVM parameter
- Set the system property via System.setProperty(«javafx.macosx.embedded», «true»); before JavaFX is initialized, used, or accessed. NOTE: You may need to change the class (that your main method is in) so it does NOT extend the JavaFX Application class.
SWT builds for FreeBSD do not exist.
ElementaryOS 5.0+ removed support for appindicators by just not including a library. You can add it back with here.
Linux/Unix: If you want to run this library as a different user, you will need to launch your application via sudo su username /bin/sh -c «DBUS_SESSION_BUS_ADDRESS=’unix:abstract=/tmp/dbus-cLtEoBPmgC’ XDG_CURRENT_DESKTOP=$XDG_CURRENT_DESKTOP program-name» , where unix:abstract=/tmp/dbus-cLtEoBPmgC from /run/user/
Linux/Unix: If you want to create a custom menu for the LAUNCHER icon, you must create a custom .desktop shortcut in order to create Actions . Credit to @tresf for figuring this out.
And then the executable path and language translations are as follows:
The test application is on Git, and a simple example is as follows:
Источник