pystray

repository·master·Indexed 20 days ago

https://github.com/moses-palmer/pystray

A 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).

Tokens
2.4K
Snippets
7
Records
15
Agent score
68%

What's inside pystray

  1. Create a system tray icon with pystray

    master
    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.
  2. Run the pystray icon mainloop in a separate thread

    master

    While 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's run() method in a background thread. This allows your primary GUI toolkit to control the main thread.

    Note for Linux users: If using the xorg backend, this works in any X session (but not under Wayland). If using GTK or AppIndicator backends, your toolkit must be based on GObject.

    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()
  3. Create a basic system tray icon

    master

    To create a system tray icon, use the pystray.Icon class. You must provide an icon image (typically a PIL.Image object) 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 optional setup argument, 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()
  4. Install AppIndicator support on Linux

    master

    To use the AppIndicator backend on Linux (which is required for runtime introspection), you must install PyGObject. Since no wheel is provided, it must be built locally. You will need compilers and pkg-config installed, plus the following distribution-specific dependencies:

    Debian/Ubuntu derivatives:

    • libcairo-dev
    • libgirepository1.0-dev

    Fedora and similar distributions:

    • libayatana-appindicator-gtk3
    • libayatana-appindicator-gtk3-devel
  5. Integrate pystray with other frameworks

    master

    Because 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.

  6. Select a pystray backend

    master

    While pystray attempts to provide a unified API, you can manually select a backend by setting the PYSTRAY_BACKEND environment variable. This is particularly useful on Linux.

    Supported Backends:

    • appindicator: Preferred for Linux. Requires appindicator or ayatana-appindicator libraries. 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 in gnome-shell.
    • win32: Default for Windows. Supports all features.
    • xorg: Fallback for Linux. Very limited; does not support menu functionality except for a default action.
  7. Add a popup menu to an icon

    master

    You can add a popup menu by passing an instance of pystray.Menu to the menu argument in the Icon constructor.

    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_MENU at runtime).

    Dynamic Menus: To allow a menu to grow or change dynamically, you can pass a callable to the Menu constructor instead of a static list. This callable should return a sequence of menu items. If external events change the state, you must call Icon.update_menu to 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()
  8. Configure MenuItem attributes

    master

    A pystray.MenuItem is defined by its text and action. 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 returning True, False, or None for togglable items.
    • radio: Visual indicator for radio button groups (not supported on macOS; check Icon.HAS_MENU_RADIO).
    • default: If True, the item is styled as the default action (not supported on Darwin/AppIndicator; check Icon.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 of Menu or 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()
  9. Display system notifications

    master

    To show a system notification, use the Icon.notify(title, message) method.

    Note: Notifications are not supported on Xorg (check Icon.HAS_NOTIFICATION at 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()
  10. Select a specific pystray backend via PYSTRAY_BACKEND

    master

    By default, pystray automatically selects a backend based on your operating system (e.g., darwin on macOS, win32 on Windows, or appindicator/gtk/xorg on Linux). You can override this behavior by setting the PYSTRAY_BACKEND environment 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:

    • dummy
    • appindicator
    • darwin
    • gtk
    • win32
    • xorg
    # Example: Force the use of the GTK backend on Linux
    export PYSTRAY_BACKEND=gtk
    python your_script.py
  11. Import Icon, Menu, and MenuItem

    master

    The primary entry points for creating system tray icons and their associated menus are Icon, Menu, and MenuItem. These are exposed at the top level of the pystray package.

    • 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 a Menu that can trigger actions.
    import pystray
    from pystray import Icon, Menu, MenuItem
    
    # Usage sketch:
    # icon = Icon("name", icon_image, menu=Menu(MenuItem("Action", callback)))