pystray
repository·master·Indexed 20 days ago
https://github.com/moses-palmer/pystrayA cross-platform Python library for creating and managing system tray icons. It provides a unified API via the Icon, Menu, and MenuItem classes to handle tray icons, popup menus, and system notifications across Windows, macOS, and Linux (supporting AppIndicator, GTK, and Xorg backends).
What's inside pystray
- pystray is a Python library used to create and manage system tray icons (also known as notification area icons). It provides a cross-platform interface for interacting with the system tray across different operating systems.
Supported platforms for pystray
masterpystray supports the following platforms:
- Linux: Specifically under Xorg, GNOME, and Ubuntu.
- macOS
- Windows
Run the pystray icon mainloop in a separate thread
masterWhile
run_detached()is strictly necessary on macOS to allow a different framework to drive the main loop, on Windows and Linux it is often simpler to just launch the icon'srun()method in a background thread. This allows your primary GUI toolkit to control the main thread.Note for Linux users: If using the
xorgbackend, this works in any X session (but not under Wayland). If usingGTKorAppIndicatorbackends, your toolkit must be based onGObject.import pystray import threading import some_toolkit # Create the icon icon = pystray.Icon( 'test name', icon=create_icon()) # Run the icon mainloop in a separate thread threading.Thread(target=icon.run).start() # Run the toolkit mainloop in the main thread some_toolkit.mainloop()Create a basic system tray icon
masterTo create a system tray icon, use the
pystray.Iconclass. You must provide an icon image (typically aPIL.Imageobject) to the constructor.Important Threading Note:
- The
icon.run()method is blocking and starts the application runloop. - On macOS,
icon.run()must be called from the main thread. - On Windows, calling
run()from a thread other than the main thread is safe. - The
run()method accepts an optionalsetupargument, which is a callable that runs in a separate thread once the icon is ready.
import pystray from PIL import Image, ImageDraw def create_image(width, height, color1, color2): image = Image.new('RGB', (width, height), color1) dc = ImageDraw.Draw(image) dc.rectangle((width // 2, 0, width, height // 2), fill=color2) dc.rectangle((0, height // 2, width // 2, height), fill=color2) return image icon = pystray.Icon( 'test name', icon=create_image(64, 64, 'black', 'white')) icon.run()- The
Install AppIndicator support on Linux
masterTo use the
AppIndicatorbackend on Linux (which is required for runtime introspection), you must installPyGObject. Since no wheel is provided, it must be built locally. You will need compilers andpkg-configinstalled, plus the following distribution-specific dependencies:Debian/Ubuntu derivatives:
libcairo-devlibgirepository1.0-dev
Fedora and similar distributions:
libayatana-appindicator-gtk3libayatana-appindicator-gtk3-devel
Integrate pystray with other frameworks
masterBecause
Icon.run()is a blocking call that starts its own runloop, it can conflict with other frameworks (like GUI toolkits) that also require the main thread for their event loop.To resolve this, use
run_detached(). This allows you to initialize the icon and then immediately return control to your framework's main loop.Select a pystray backend
masterWhile
pystrayattempts to provide a unified API, you can manually select a backend by setting thePYSTRAY_BACKENDenvironment variable. This is particularly useful on Linux.Supported Backends:
appindicator: Preferred for Linux. Requiresappindicatororayatana-appindicatorlibraries. Supports most features except menu default actions.darwin: Default for macOS. Supports all features.gtk: Linux backend using GTK. Supports all features, but may require a third-party plugin to show icons ingnome-shell.win32: Default for Windows. Supports all features.xorg: Fallback for Linux. Very limited; does not support menu functionality except for a default action.
Add a popup menu to an icon
masterYou can add a popup menu by passing an instance of
pystray.Menuto themenuargument in theIconconstructor.Platform Support:
- Windows: The menu appears when the right-hand button is pressed.
- Other platforms: The menu appears when the icon is clicked.
- Xorg: Menus are not supported (check
Icon.HAS_MENUat runtime).
Dynamic Menus: To allow a menu to grow or change dynamically, you can pass a callable to the
Menuconstructor instead of a static list. This callable should return a sequence of menu items. If external events change the state, you must callIcon.update_menuto refresh the display.from pystray import Icon as icon, Menu as menu, MenuItem as item # Example of a dynamic menu using a callable icon('test', create_image(), menu=menu(lambda: ( item('Dynamic Item 1', lambda i, m: print('1')), item('Dynamic Item 2', lambda i, m: print('2')), ))).run()Configure MenuItem attributes
masterA
pystray.MenuItemis defined by itstextandaction. Most other properties can be passed as static values or callables that return the current value, allowing for dynamic updates every time the menu is opened.Attributes:
text: The label of the item.action: A callable invoked when the item is selected.checked: Determines if the item shows a check box. Use a callable returningTrue,False, orNonefor togglable items.radio: Visual indicator for radio button groups (not supported on macOS; checkIcon.HAS_MENU_RADIO).default: IfTrue, the item is styled as the default action (not supported on Darwin/AppIndicator; checkIcon.HAS_DEFAULT).visible: Boolean or callable returning boolean for visibility.enabled: Boolean or callable returning boolean for whether the item is clickable.submenu: An instance ofMenuor a tuple of entries attached to the item.
from pystray import Icon as icon, Menu as menu, MenuItem as item state = False def on_clicked(icon, item): global state state = not item.checked # A checkable menu item icon('test', create_image(), menu=menu( item('Checkable', on_clicked, checked=lambda item: state) )).run()Display system notifications
masterTo show a system notification, use the
Icon.notify(title, message)method.Note: Notifications are not supported on Xorg (check
Icon.HAS_NOTIFICATIONat runtime).from pystray import Icon as icon, Menu as menu, MenuItem as item icon('test', create_image(), menu=menu( item('Show message', lambda i, m: i.notify('Hello World!')) )).run()Select a specific pystray backend via PYSTRAY_BACKEND
masterBy default,
pystrayautomatically selects a backend based on your operating system (e.g.,darwinon macOS,win32on Windows, orappindicator/gtk/xorgon Linux). You can override this behavior by setting thePYSTRAY_BACKENDenvironment variable to one of the supported backend names. This is useful for testing or forcing a specific implementation if multiple are available.Supported backend names include:
dummyappindicatordarwingtkwin32xorg
# Example: Force the use of the GTK backend on Linux export PYSTRAY_BACKEND=gtk python your_script.pyImport Icon, Menu, and MenuItem
masterThe primary entry points for creating system tray icons and their associated menus are
Icon,Menu, andMenuItem. These are exposed at the top level of thepystraypackage.Icon: The main class used to create and manage the system tray icon.Menu: A container for grouping menu items.MenuItem: An individual entry within aMenuthat can trigger actions.
import pystray from pystray import Icon, Menu, MenuItem # Usage sketch: # icon = Icon("name", icon_image, menu=Menu(MenuItem("Action", callback)))