Skip to content

Commit d05166f

Browse files
fix(linux): migrate to qt tray (#104)
1 parent 6fa152f commit d05166f

15 files changed

Lines changed: 1726 additions & 499 deletions

.github/workflows/ci.yml

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
github_token: ${{ secrets.GITHUB_TOKEN }}
3737

3838
build:
39-
name: Build (${{ matrix.os }} - ${{ matrix.appindicator || 'default' }})
39+
name: Build (${{ matrix.os }}${{ matrix.qt_version && format(', Qt{0}', matrix.qt_version) || '' }})
4040
defaults:
4141
run:
4242
shell: ${{ matrix.shell }}
@@ -49,16 +49,16 @@ jobs:
4949
include:
5050
- os: macos-latest
5151
shell: "bash"
52+
qt_version: ''
5253
- os: ubuntu-latest
53-
appindicator: "libayatana-appindicator3-dev"
54-
appindicator_type: "ayatana"
5554
shell: "bash"
55+
qt_version: '5'
5656
- os: ubuntu-latest
57-
appindicator: "libappindicator3-dev"
58-
appindicator_type: "legacy"
5957
shell: "bash"
58+
qt_version: '6'
6059
- os: windows-latest
6160
shell: "msys2 {0}"
61+
qt_version: ''
6262
steps:
6363
- name: Checkout
6464
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -67,23 +67,41 @@ jobs:
6767

6868
- name: Setup Dependencies Linux
6969
if: runner.os == 'Linux'
70+
env:
71+
QT_VERSION: ${{ matrix.qt_version }}
7072
run: |
73+
dependencies=(
74+
"adwaita-icon-theme"
75+
"build-essential"
76+
"cmake"
77+
"imagemagick"
78+
"ninja-build"
79+
"xvfb"
80+
)
81+
82+
if [[ "${QT_VERSION}" == "5" ]]; then
83+
dependencies+=(
84+
"libqt5svg5-dev"
85+
"qt5-gtk-platformtheme"
86+
"qtbase5-dev"
87+
)
88+
elif [[ "${QT_VERSION}" == "6" ]]; then
89+
dependencies+=(
90+
"qt6-base-dev"
91+
"qt6-svg-dev"
92+
)
93+
else
94+
echo "Unsupported QT_VERSION: ${QT_VERSION}"
95+
exit 1
96+
fi
97+
7198
sudo apt-get update
72-
sudo apt-get install -y \
73-
build-essential \
74-
cmake \
75-
${{ matrix.appindicator }} \
76-
imagemagick \
77-
libglib2.0-dev \
78-
libnotify-dev \
79-
ninja-build \
80-
xvfb
99+
sudo apt-get install -y "${dependencies[@]}"
81100
82101
- name: Setup virtual desktop
83102
if: runner.os == 'Linux'
84103
uses: LizardByte/actions/actions/virtual_desktop@0affa4f7bcb27562658960eee840eff8ff844578 # v2026.328.161128
85104
with:
86-
appindicator-version: ${{ matrix.appindicator_type }}
87105
environment: mate
88106

89107
- name: Setup Dependencies macOS
@@ -169,7 +187,7 @@ jobs:
169187
echo "python-path=${python_path}"
170188
echo "python-path=${python_path}" >> "${GITHUB_OUTPUT}"
171189
172-
- name: Build
190+
- name: Configure
173191
run: |
174192
mkdir -p build
175193
@@ -186,7 +204,9 @@ jobs:
186204
-B build \
187205
-G Ninja \
188206
-S .
189-
ninja -C build
207+
208+
- name: Build
209+
run: ninja -C build
190210

191211
- name: Init tray icon (Windows)
192212
if: runner.os == 'Windows'
@@ -228,6 +248,8 @@ jobs:
228248
# TODO: tests randomly hang on Linux, https://github.com/LizardByte/tray/issues/45
229249
timeout-minutes: 3
230250
working-directory: build/tests
251+
env:
252+
QT_QPA_PLATFORMTHEME: ${{ runner.os == 'Linux' && matrix.qt_version == '5' && 'gtk3' || '' }}
231253
run: ./test_tray --gtest_color=yes --gtest_output=xml:test_results.xml
232254

233255
- name: Upload screenshots
@@ -236,7 +258,7 @@ jobs:
236258
(steps.test.outcome == 'success' || steps.test.outcome == 'failure')
237259
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
238260
with:
239-
name: tray-screenshots-${{ runner.os }}${{ matrix.appindicator && format('-{0}', matrix.appindicator) || '' }}
261+
name: tray-screenshots-${{ runner.os }}${{ matrix.qt_version && format('-qt{0}', matrix.qt_version) || '' }}
240262
path: build/tests/screenshots
241263
if-no-files-found: error
242264

@@ -263,10 +285,7 @@ jobs:
263285
- name: Set codecov flags
264286
id: codecov_flags
265287
run: |
266-
flags="${{ runner.os }}"
267-
if [ -n "${{ matrix.appindicator }}" ]; then
268-
flags="${flags},${{ matrix.appindicator }}"
269-
fi
288+
flags="${{ runner.os }}${{ matrix.qt_version && format('-qt{0}', matrix.qt_version) || '' }}"
270289
echo "flags=${flags}" >> "${GITHUB_OUTPUT}"
271290
272291
- name: Upload coverage

CMakeLists.txt

Lines changed: 76 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,99 +5,133 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR) # target_link_directories
55
project(tray VERSION 0.0.0
66
DESCRIPTION "A cross-platform system tray library"
77
HOMEPAGE_URL "https://app.lizardbyte.dev"
8-
LANGUAGES C)
8+
LANGUAGES C CXX)
99

1010
set(PROJECT_LICENSE "MIT")
1111

12+
set(TRAY_IS_TOP_LEVEL OFF)
13+
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
14+
set(TRAY_IS_TOP_LEVEL ON)
15+
endif()
16+
1217
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
1318
message(STATUS "Setting build type to 'Release' as none was specified.")
1419
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
1520
endif()
1621

17-
# Add our custom CMake modules to the global path
18-
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
22+
# Add our custom CMake modules without overriding parent project settings.
23+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
1924

2025
#
2126
# Project optional configuration
2227
#
23-
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
24-
option(BUILD_DOCS "Build documentation" ON)
25-
option(BUILD_TESTS "Build tests" ON)
26-
endif()
28+
option(BUILD_DOCS "Build documentation" ${TRAY_IS_TOP_LEVEL})
29+
option(BUILD_TESTS "Build tests" ${TRAY_IS_TOP_LEVEL})
30+
option(BUILD_EXAMPLE "Build example app" ${TRAY_IS_TOP_LEVEL})
2731

2832
# Generate 'compile_commands.json' for clang_complete
2933
set(CMAKE_COLOR_MAKEFILE ON)
3034
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
3135

32-
find_package (PkgConfig REQUIRED)
36+
find_package(PkgConfig)
3337

3438
file(GLOB TRAY_SOURCES
35-
"${CMAKE_SOURCE_DIR}/src/*.h"
36-
"${CMAKE_SOURCE_DIR}/icons/*.ico"
37-
"${CMAKE_SOURCE_DIR}/icons/*.png")
39+
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.h"
40+
)
41+
42+
set(TRAY_ICON_ICO "${CMAKE_CURRENT_SOURCE_DIR}/icons/icon.ico")
43+
set(TRAY_ICON_PNG "${CMAKE_CURRENT_SOURCE_DIR}/icons/icon.png")
44+
set(TRAY_ICON_SVG "${CMAKE_CURRENT_SOURCE_DIR}/icons/icon.svg")
45+
set(TRAY_ICON_FILES
46+
"${TRAY_ICON_ICO}"
47+
"${TRAY_ICON_PNG}"
48+
"${TRAY_ICON_SVG}"
49+
)
50+
51+
set(_TRAY_ICON_ICO "${TRAY_ICON_ICO}" CACHE INTERNAL "Default tray ICO icon path")
52+
set(_TRAY_ICON_PNG "${TRAY_ICON_PNG}" CACHE INTERNAL "Default tray PNG icon path")
53+
set(_TRAY_ICON_SVG "${TRAY_ICON_SVG}" CACHE INTERNAL "Default tray SVG icon path")
54+
55+
# Copy default tray icon files into the output directory of the specified target.
56+
function(tray_copy_default_icons target_name)
57+
if(NOT TARGET "${target_name}")
58+
message(FATAL_ERROR "tray_copy_default_icons expected an existing target: ${target_name}")
59+
endif()
60+
61+
foreach(icon_file IN LISTS TRAY_ICON_FILES)
62+
add_custom_command(TARGET "${target_name}" POST_BUILD
63+
COMMAND ${CMAKE_COMMAND} -E copy_if_different
64+
"${icon_file}"
65+
"$<TARGET_FILE_DIR:${target_name}>"
66+
COMMENT "Copying ${icon_file} to $<TARGET_FILE_DIR:${target_name}>")
67+
endforeach()
68+
endfunction()
3869

3970
if(WIN32)
40-
list(APPEND TRAY_SOURCES "${CMAKE_SOURCE_DIR}/src/tray_windows.c")
71+
list(APPEND TRAY_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/tray_windows.c")
4172
else()
4273
if(UNIX)
4374
if(APPLE)
4475
find_library(COCOA Cocoa REQUIRED)
45-
list(APPEND TRAY_SOURCES "${CMAKE_SOURCE_DIR}/src/tray_darwin.m")
76+
list(APPEND TRAY_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/tray_darwin.m")
4677
else()
47-
find_package(APPINDICATOR REQUIRED)
48-
find_package(LibNotify REQUIRED)
49-
list(APPEND TRAY_SOURCES "${CMAKE_SOURCE_DIR}/src/tray_linux.c")
78+
find_package(Qt6 COMPONENTS Widgets DBus Svg)
79+
if(Qt6_FOUND)
80+
set(TRAY_QT_VERSION 6)
81+
else()
82+
find_package(Qt5 REQUIRED COMPONENTS Widgets DBus Svg)
83+
set(TRAY_QT_VERSION 5)
84+
endif()
85+
set(TRAY_QT_VERSION # cmake-lint: disable=C0103
86+
"${TRAY_QT_VERSION}"
87+
CACHE INTERNAL "Qt major version selected by tray"
88+
)
89+
set(CMAKE_AUTOMOC ON)
90+
list(APPEND TRAY_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/tray_linux.cpp")
5091
endif()
5192
endif()
5293
endif()
5394

5495
add_library(${PROJECT_NAME} STATIC ${TRAY_SOURCES})
5596
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99)
97+
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17)
98+
target_include_directories(${PROJECT_NAME}
99+
PUBLIC
100+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
101+
$<INSTALL_INTERFACE:include>)
56102

57103
if(WIN32)
58-
list(APPEND TRAY_DEFINITIONS TRAY_WINAPI=1 WIN32_LEAN_AND_MEAN NOMINMAX)
59104
if(MSVC)
60105
list(APPEND TRAY_COMPILE_OPTIONS "/MT$<$<CONFIG:Debug>:d>")
61106
endif()
62107
else()
63108
if(UNIX)
64109
if(APPLE)
65-
list(APPEND TRAY_DEFINITIONS TRAY_APPKIT=1)
66110
list(APPEND TRAY_EXTERNAL_LIBRARIES ${COCOA})
67111
else()
68-
list(APPEND TRAY_COMPILE_OPTIONS ${APPINDICATOR_CFLAGS})
69-
list(APPEND TRAY_EXTERNAL_DIRECTORIES ${APPINDICATOR_LIBRARY_DIRS})
70-
list(APPEND TRAY_DEFINITIONS TRAY_APPINDICATOR=1)
71-
if(APPINDICATOR_AYATANA)
72-
list(APPEND TRAY_DEFINITIONS TRAY_AYATANA_APPINDICATOR=1)
112+
if(TRAY_QT_VERSION EQUAL 6)
113+
list(APPEND TRAY_EXTERNAL_LIBRARIES Qt6::Widgets Qt6::DBus Qt6::Svg)
114+
else()
115+
list(APPEND TRAY_EXTERNAL_LIBRARIES Qt5::Widgets Qt5::DBus Qt5::Svg)
73116
endif()
74-
if(APPINDICATOR_LEGACY)
75-
list(APPEND TRAY_DEFINITIONS TRAY_LEGACY_APPINDICATOR=1)
76-
endif()
77-
list(APPEND TRAY_LIBNOTIFY=1)
78-
list(APPEND TRAY_EXTERNAL_LIBRARIES ${APPINDICATOR_LIBRARIES} ${LIBNOTIFY_LIBRARIES})
79-
80-
include_directories(SYSTEM ${APPINDICATOR_INCLUDE_DIRS} ${LIBNOTIFY_INCLUDE_DIRS})
81-
link_directories(${APPINDICATOR_LIBRARY_DIRS} ${LIBNOTIFY_LIBRARY_DIRS})
82117
endif()
83118
endif()
84119
endif()
85120

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

88-
add_executable(tray_example "${CMAKE_SOURCE_DIR}/src/example.c")
89-
target_link_libraries(tray_example tray::tray)
90-
91-
configure_file("${CMAKE_SOURCE_DIR}/icons/icon.ico" "${CMAKE_BINARY_DIR}/icon.ico" COPYONLY)
92-
configure_file("${CMAKE_SOURCE_DIR}/icons/icon.png" "${CMAKE_BINARY_DIR}/icon.png" COPYONLY)
93-
94-
INSTALL(TARGETS tray tray DESTINATION lib)
123+
if(BUILD_EXAMPLE)
124+
add_executable(tray_example "${CMAKE_CURRENT_SOURCE_DIR}/src/example.c")
125+
target_link_libraries(tray_example tray::tray)
126+
tray_copy_default_icons(tray_example)
127+
endif()
95128

96-
IF(NOT WIN32)
97-
INSTALL(FILES tray.h DESTINATION include)
98-
ENDIF()
129+
if(TRAY_IS_TOP_LEVEL)
130+
install(TARGETS tray DESTINATION lib)
131+
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/tray.h" DESTINATION include)
132+
install(FILES ${TRAY_ICON_FILES} DESTINATION share/tray/icons)
133+
endif()
99134

100-
target_compile_definitions(${PROJECT_NAME} PRIVATE ${TRAY_DEFINITIONS})
101135
target_compile_options(${PROJECT_NAME} PRIVATE ${TRAY_COMPILE_OPTIONS})
102136
target_link_directories(${PROJECT_NAME} PRIVATE ${TRAY_EXTERNAL_DIRECTORIES})
103137
target_link_libraries(${PROJECT_NAME} PRIVATE ${TRAY_EXTERNAL_LIBRARIES})

README.md

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@ The code is C++ friendly and will compile fine in C++98 and up. This is a fork o
1515
This fork adds the following features:
1616

1717
- system tray notifications
18-
- support for both linux appindicator versions
1918
- unit tests
2019
- code coverage
21-
- refactored code, e.g. moved source code into the `src` directory
22-
- doxygen documentation, and readthedocs configuration
20+
- refactored code, e.g., moved source code into the `src` directory
21+
- doxygen documentation and readthedocs configuration
2322

2423
## Screenshots
2524

@@ -33,32 +32,47 @@ This fork adds the following features:
3332

3433
## Supported platforms
3534

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

4039
## Prerequisites
4140

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

4544
### Linux Dependencies
4645

46+
Install either Qt6 _or_ Qt5 development packages. The Linux backend requires
47+
Qt Widgets, DBus, and Svg modules.
48+
4749
<div class="tabbed">
4850

4951
- <b class="tab-title">Arch</b>
5052
```bash
51-
sudo pacman -S libayatana-appindicator
53+
# Qt6
54+
sudo pacman -S qt6-base qt6-svg
55+
56+
# Qt5
57+
sudo pacman -S qt5-base qt5-svg
5258
```
5359

5460
- <b class="tab-title">Debian/Ubuntu</b>
5561
```bash
56-
sudo apt install libappindicator3-dev
62+
# Qt6
63+
sudo apt install qt6-base-dev qt6-svg-dev
64+
65+
# Qt5
66+
sudo apt install qtbase5-dev libqt5svg5-dev
5767
```
5868

5969
- <b class="tab-title">Fedora</b>
6070
```bash
61-
sudo dnf install libappindicator-gtk3-devel
71+
# Qt6
72+
sudo dnf install qt6-qtbase-devel qt6-qtsvg-devel
73+
74+
# Qt5
75+
sudo dnf install qt5-qtbase-devel qt5-qtsvg-devel
6276
```
6377

6478
</div>

0 commit comments

Comments
 (0)