- C++ 63.2%
- C 21.6%
- CMake 9.7%
- Objective-C 5.5%
|
|
||
|---|---|---|
| .github | ||
| .run | ||
| cmake | ||
| docs | ||
| icons | ||
| src | ||
| tests | ||
| third-party | ||
| .clang-format | ||
| .gitattributes | ||
| .gitignore | ||
| .gitmodules | ||
| .readthedocs.yaml | ||
| .sonarcloud.properties | ||
| CMakeLists.txt | ||
| LICENSE | ||
| README.md | ||
| renovate.json | ||
| sonar-project.properties | ||
| tray.svg | ||
tray
Cross-platform implementation of a system tray icon with a popup menu and notifications.
Overview
ℹ️ About
Cross-platform, super tiny C99 implementation of a system tray icon with a popup menu and notifications.
The code is C++ friendly and will compile fine in C++98 and up. This is a fork of dmikushin/tray and is intended to add additional features required for our own Sunshine project.
This fork adds the following features:
- system tray notifications
- unit tests
- code coverage
- refactored code, e.g., moved source code into the
srcdirectory - doxygen documentation and readthedocs configuration
🖼️ Screenshots
- Linux
 - macOS
 - Windows

🖥️ Supported platforms
- Linux/Qt (Qt5 or Qt6 Widgets)
- Windows XP or newer (shellapi.h)
- MacOS (Cocoa/AppKit)
📋 Prerequisites
- CMake
- Ninja, to have the same build commands on all platforms.
Linux Dependencies
Install either Qt6 or Qt5 as well as libnotify development packages. The Linux backend requires libnotify and Qt Widgets+Svg modules.
-
Arch
# Qt6 sudo pacman -S qt6-base qt6-svg libnotify # Qt5 sudo pacman -S qt5-base qt5-svg libnotify -
Debian/Ubuntu
# Qt6 sudo apt install qt6-base-dev qt6-svg-dev libnotify-dev # Qt5 sudo apt install qtbase5-dev libqt5svg5-dev libnotify-dev -
Fedora
# Qt6 sudo dnf install qt6-qtbase-devel qt6-qtsvg-devel libnotify-devel # Qt5 sudo dnf install qt5-qtbase-devel qt5-qtsvg-devel libnotify-devel
🛠️ Building
mkdir -p build
cmake -G Ninja -B build -S .
ninja -C build
⚙️ Python Tooling
Install uv and initialize the shared tooling submodule:
git submodule update --init --recursive third-party/lizardbyte-common
uv run --project third-party/lizardbyte-common --locked --only-group lint-c \
python third-party/lizardbyte-common/scripts/update_clang_format.py
▶️ Demo
Execute the tray_example application:
./build/tray_example
✅ Tests
Execute the tests application:
./build/tests/test_tray
📚 API
Tray structure defines an icon and a menu. Menu is a NULL-terminated array of items. Menu item defines menu text, menu checked and disabled (grayed) flags and a callback with some optional context pointer.
struct tray {
char *icon;
struct tray_menu *menu;
};
struct tray_menu {
char *text;
int disabled;
int checked;
void (*cb)(struct tray_menu *);
void *context;
struct tray_menu *submenu;
};
int tray_init(struct tray *)- creates tray icon. Returns -1 if tray icon/menu can't be created.void tray_update(struct tray *)- updates tray icon and menu.int tray_loop(int blocking)- runs one iteration of the UI loop. Returns -1 iftray_exit()has been called.void tray_exit()- terminates UI loop.
All functions are meant to be called from the UI thread only.
Menu arrays must be terminated with a NULL item, e.g. the last item in the array must have text field set to NULL.
📄 License
This software is distributed under MIT license, so feel free to integrate it in your commercial products.