Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 7 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}

build:
name: Build (${{ matrix.os }} - ${{ matrix.appindicator || 'default' }})
name: Build (${{ matrix.os }})
defaults:
run:
shell: ${{ matrix.shell }}
Expand All @@ -50,12 +50,6 @@ jobs:
- os: macos-latest
shell: "bash"
- os: ubuntu-latest
appindicator: "libayatana-appindicator3-dev"
appindicator_type: "ayatana"
shell: "bash"
- os: ubuntu-latest
appindicator: "libappindicator3-dev"
appindicator_type: "legacy"
shell: "bash"
- os: windows-latest
shell: "msys2 {0}"
Expand All @@ -70,20 +64,19 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y \
adwaita-icon-theme \
build-essential \
cmake \
${{ matrix.appindicator }} \
imagemagick \
libglib2.0-dev \
libnotify-dev \
ninja-build \
qt5-gtk-platformtheme \
qtbase5-dev \
xvfb
- name: Setup virtual desktop
if: runner.os == 'Linux'
uses: LizardByte/actions/actions/virtual_desktop@70bb8d394d1c92f6113aeec6ae9cc959a5763d15 # v2026.227.200013
with:
appindicator-version: ${{ matrix.appindicator_type }}
environment: mate

- name: Setup Dependencies macOS
Expand Down Expand Up @@ -228,6 +221,8 @@ jobs:
# TODO: tests randomly hang on Linux, https://github.com/LizardByte/tray/issues/45
timeout-minutes: 3
working-directory: build/tests
env:
QT_QPA_PLATFORMTHEME: gtk3
run: ./test_tray --gtest_color=yes --gtest_output=xml:test_results.xml

- name: Upload screenshots
Expand All @@ -236,7 +231,7 @@ jobs:
(steps.test.outcome == 'success' || steps.test.outcome == 'failure')
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: tray-screenshots-${{ runner.os }}${{ matrix.appindicator && format('-{0}', matrix.appindicator) || '' }}
name: tray-screenshots-${{ runner.os }}
path: build/tests/screenshots
if-no-files-found: error

Expand Down Expand Up @@ -264,9 +259,6 @@ jobs:
id: codecov_flags
run: |
flags="${{ runner.os }}"
if [ -n "${{ matrix.appindicator }}" ]; then
flags="${flags},${{ matrix.appindicator }}"
fi
echo "flags=${flags}" >> "${GITHUB_OUTPUT}"
- name: Upload coverage
Expand Down
51 changes: 25 additions & 26 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR) # target_link_directories
project(tray VERSION 0.0.0
DESCRIPTION "A cross-platform system tray library"
HOMEPAGE_URL "https://app.lizardbyte.dev"
LANGUAGES C)
LANGUAGES C CXX)

set(PROJECT_LICENSE "MIT")

Expand All @@ -29,30 +29,37 @@ endif()
set(CMAKE_COLOR_MAKEFILE ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

find_package (PkgConfig REQUIRED)
find_package(PkgConfig)

file(GLOB TRAY_SOURCES
"${CMAKE_SOURCE_DIR}/src/*.h"
"${CMAKE_SOURCE_DIR}/icons/*.ico"
"${CMAKE_SOURCE_DIR}/icons/*.png")
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/icons/*.ico"
"${CMAKE_CURRENT_SOURCE_DIR}/icons/*.png")

if(WIN32)
list(APPEND TRAY_SOURCES "${CMAKE_SOURCE_DIR}/src/tray_windows.c")
list(APPEND TRAY_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/tray_windows.c")
else()
if(UNIX)
if(APPLE)
find_library(COCOA Cocoa REQUIRED)
list(APPEND TRAY_SOURCES "${CMAKE_SOURCE_DIR}/src/tray_darwin.m")
list(APPEND TRAY_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/tray_darwin.m")
else()
find_package(APPINDICATOR REQUIRED)
find_package(LibNotify REQUIRED)
list(APPEND TRAY_SOURCES "${CMAKE_SOURCE_DIR}/src/tray_linux.c")
find_package(Qt6 QUIET COMPONENTS Widgets DBus)
if(Qt6_FOUND)
set(TRAY_QT_VERSION 6)
else()
find_package(Qt5 REQUIRED COMPONENTS Widgets DBus)
set(TRAY_QT_VERSION 5)
endif()
set(CMAKE_AUTOMOC ON)
list(APPEND TRAY_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/tray_linux.cpp")
endif()
endif()
endif()

add_library(${PROJECT_NAME} STATIC ${TRAY_SOURCES})
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14)

if(WIN32)
list(APPEND TRAY_DEFINITIONS TRAY_WINAPI=1 WIN32_LEAN_AND_MEAN NOMINMAX)
Expand All @@ -65,31 +72,23 @@ else()
list(APPEND TRAY_DEFINITIONS TRAY_APPKIT=1)
list(APPEND TRAY_EXTERNAL_LIBRARIES ${COCOA})
else()
list(APPEND TRAY_COMPILE_OPTIONS ${APPINDICATOR_CFLAGS})
list(APPEND TRAY_EXTERNAL_DIRECTORIES ${APPINDICATOR_LIBRARY_DIRS})
list(APPEND TRAY_DEFINITIONS TRAY_APPINDICATOR=1)
if(APPINDICATOR_AYATANA)
list(APPEND TRAY_DEFINITIONS TRAY_AYATANA_APPINDICATOR=1)
endif()
if(APPINDICATOR_LEGACY)
list(APPEND TRAY_DEFINITIONS TRAY_LEGACY_APPINDICATOR=1)
list(APPEND TRAY_DEFINITIONS TRAY_QT=1)
if(TRAY_QT_VERSION EQUAL 6)
list(APPEND TRAY_EXTERNAL_LIBRARIES Qt6::Widgets Qt6::DBus)
else()
list(APPEND TRAY_EXTERNAL_LIBRARIES Qt5::Widgets Qt5::DBus)
endif()
list(APPEND TRAY_LIBNOTIFY=1)
list(APPEND TRAY_EXTERNAL_LIBRARIES ${APPINDICATOR_LIBRARIES} ${LIBNOTIFY_LIBRARIES})

include_directories(SYSTEM ${APPINDICATOR_INCLUDE_DIRS} ${LIBNOTIFY_INCLUDE_DIRS})
link_directories(${APPINDICATOR_LIBRARY_DIRS} ${LIBNOTIFY_LIBRARY_DIRS})
endif()
endif()
endif()

add_library(tray::tray ALIAS ${PROJECT_NAME})

add_executable(tray_example "${CMAKE_SOURCE_DIR}/src/example.c")
add_executable(tray_example "${CMAKE_CURRENT_SOURCE_DIR}/src/example.c")
target_link_libraries(tray_example tray::tray)

configure_file("${CMAKE_SOURCE_DIR}/icons/icon.ico" "${CMAKE_BINARY_DIR}/icon.ico" COPYONLY)
configure_file("${CMAKE_SOURCE_DIR}/icons/icon.png" "${CMAKE_BINARY_DIR}/icon.png" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/icons/icon.ico" "${CMAKE_CURRENT_BINARY_DIR}/icon.ico" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/icons/icon.png" "${CMAKE_CURRENT_BINARY_DIR}/icon.png" COPYONLY)

INSTALL(TARGETS tray tray DESTINATION lib)

Expand Down
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ The code is C++ friendly and will compile fine in C++98 and up. This is a fork o
This fork adds the following features:

- system tray notifications
- support for both linux appindicator versions
- unit tests
- code coverage
- refactored code, e.g. moved source code into the `src` directory
- doxygen documentation, and readthedocs configuration
- refactored code, e.g., moved source code into the `src` directory
- doxygen documentation and readthedocs configuration

## Screenshots

Expand All @@ -33,32 +32,32 @@ This fork adds the following features:

## Supported platforms

* Linux/Gtk (libayatana-appindicator3 or libappindicator3)
* Linux/Qt (Qt5 or Qt6 Widgets)
* Windows XP or newer (shellapi.h)
* MacOS (Cocoa/AppKit)

## Prerequisites

* CMake
* [Ninja](https://ninja-build.org/), in order to have the same build commands on all platforms
* [Ninja](https://ninja-build.org/), to have the same build commands on all platforms.

### Linux Dependencies

<div class="tabbed">

- <b class="tab-title">Arch</b>
```bash
sudo pacman -S libayatana-appindicator
sudo pacman -S qt6-base
```

- <b class="tab-title">Debian/Ubuntu</b>
```bash
sudo apt install libappindicator3-dev
sudo apt install qtbase5-dev
```

- <b class="tab-title">Fedora</b>
```bash
sudo dnf install libappindicator-gtk3-devel
sudo dnf install qt6-qtbase-devel
```

</div>
Expand Down
8 changes: 4 additions & 4 deletions src/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@
#if defined(_WIN32) || defined(_WIN64)
#define TRAY_WINAPI 1 ///< Use WinAPI.
#elif defined(__linux__) || defined(linux) || defined(__linux)
#define TRAY_APPINDICATOR 1
#define TRAY_QT 1
#elif defined(__APPLE__) || defined(__MACH__)
#define TRAY_APPKIT 1
#endif

// local includes
#include "tray.h"

#if TRAY_APPINDICATOR
#define TRAY_ICON1 "mail-message-new"
#define TRAY_ICON2 "mail-message-new"
#if TRAY_QT
#define TRAY_ICON1 "icon.png"
#define TRAY_ICON2 "icon.png"
#elif TRAY_APPKIT
#define TRAY_ICON1 "icon.png"
#define TRAY_ICON2 "icon.png"
Expand Down
20 changes: 20 additions & 0 deletions src/tray.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,31 @@ extern "C" {
*/
void tray_show_menu(void);

/**
* @brief Simulate a notification click, invoking the notification callback (for testing purposes).
*
* On Linux (Qt): triggers the stored notification callback as if the user clicked the notification.
* On other platforms: no-op.
*/
void tray_simulate_notification_click(void);

/**
* @brief Terminate UI loop.
*/
void tray_exit(void);

/**
* @brief Set a callback for log messages produced by the tray library.
*
* On Linux the callback is installed as a Qt message handler so all Qt
* diagnostic output is routed through it. On other platforms this function
* is a no-op.
*
* @param cb Callback invoked with level (0=debug, 1=info, 2=warning, 3=error)
* and the message string. Pass NULL to restore the default logging behaviour.
*/
void tray_set_log_callback(void (*cb)(int level, const char *msg));

#if defined(TRAY_WINAPI)
/**
* @brief Get the tray window handle.
Expand Down
10 changes: 10 additions & 0 deletions src/tray_darwin.m
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ void tray_show_menu(void) {
[statusItem popUpStatusItemMenu:statusItem.menu];
}

void tray_simulate_notification_click(void) {
// macOS notification clicks are handled by the OS notification center.
// Simulation is not supported here.
}

void tray_set_log_callback(void (*cb)(int level, const char *msg)) {
// Qt is not used on macOS; log routing is not applicable.
(void) cb;
}

void tray_exit(void) {
// Remove the status item from the status bar on the main thread
// NSStatusBar operations must be performed on the main thread
Expand Down
Loading
Loading