Skip to content

fix(linux): migrate to qt tray#104

Merged
ReenigneArcher merged 23 commits intomasterfrom
fix/linux/migrate-to-qt-tray
Mar 29, 2026
Merged

fix(linux): migrate to qt tray#104
ReenigneArcher merged 23 commits intomasterfrom
fix/linux/migrate-to-qt-tray

Conversation

@ReenigneArcher
Copy link
Copy Markdown
Member

Description

Migrate to qt5/6 for Linux tray.

Screenshot

Issues Fixed or Closed

Roadmap Issues

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Unit tests have been added or updated for any new or modified functionality

AI Usage

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 24, 2026

Codecov Report

❌ Patch coverage is 58.11518% with 240 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.75%. Comparing base (6fa152f) to head (f207e17).
⚠️ Report is 1 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/tray_linux.cpp 59.46% 147 Missing and 80 partials ⚠️
src/tray_darwin.m 0.00% 9 Missing ⚠️
src/tray_windows.c 0.00% 4 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (6fa152f) and HEAD (f207e17). Click for more details.

HEAD has 4 uploads less than BASE
Flag BASE (6fa152f) HEAD (f207e17)
libappindicator3-dev 1 0
Linux 2 0
libayatana-appindicator3-dev 1 0
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #104      +/-   ##
==========================================
- Coverage   73.06%   63.75%   -9.32%     
==========================================
  Files           4        4              
  Lines         427      858     +431     
  Branches       83      313     +230     
==========================================
+ Hits          312      547     +235     
- Misses         72      208     +136     
- Partials       43      103      +60     
Flag Coverage Δ
Linux ?
Linux-qt5 57.11% <59.46%> (?)
Linux-qt6 57.11% <59.46%> (?)
Windows 70.67% <0.00%> (-0.90%) ⬇️
libappindicator3-dev ?
libayatana-appindicator3-dev ?
macOS 59.29% <0.00%> (-5.14%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/example.c 0.00% <ø> (ø)
src/tray_windows.c 79.45% <0.00%> (-1.21%) ⬇️
src/tray_darwin.m 77.90% <0.00%> (-9.11%) ⬇️
src/tray_linux.cpp 59.46% <59.46%> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6fa152f...f207e17. Read the comment docs.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 26, 2026

Last Updated 2026-03-29 12:38:05 UTC
Source Run CI Run #503
Commit f207e17341a83280d1021c5b7971c7c57ade5405

Screenshot Comparison

PR #104 screenshots vs screenshots baseline.

Matrix: Linux-libappindicator3-dev

Image Baseline PR
tray_icon_initial.png
tray_menu_checkbox_checked.png
tray_menu_checkbox_unchecked.png
tray_menu_shown.png
tray_notification_displayed.png

Matrix: Linux-libayatana-appindicator3-dev

Image Baseline PR
tray_icon_initial.png
tray_menu_checkbox_checked.png
tray_menu_checkbox_unchecked.png
tray_menu_shown.png
tray_notification_displayed.png

Matrix: Linux-qt5

Image Baseline PR
tray_icon_initial.png
tray_icon_svg.png
tray_icon_themed.png
tray_menu_checkbox_checked.png
tray_menu_checkbox_unchecked.png
tray_menu_left_click.png
tray_menu_shown.png
tray_notification_displayed.png
tray_notification_themed_icon.png

Matrix: Linux-qt6

Image Baseline PR
tray_icon_initial.png
tray_icon_svg.png
tray_icon_themed.png
tray_menu_checkbox_checked.png
tray_menu_checkbox_unchecked.png
tray_menu_left_click.png
tray_menu_shown.png
tray_notification_displayed.png
tray_notification_themed_icon.png

Matrix: Windows

Image Baseline PR
tray_icon_initial.png
tray_menu_checkbox_checked.png
tray_menu_checkbox_unchecked.png
tray_menu_shown.png
tray_notification_displayed.png

Matrix: macOS

Image Baseline PR
tray_icon_initial.png
tray_menu_checkbox_checked.png
tray_menu_checkbox_unchecked.png
tray_menu_shown.png
tray_notification_displayed.png

@ReenigneArcher ReenigneArcher force-pushed the fix/linux/migrate-to-qt-tray branch 2 times, most recently from 0ce906a to 66665fb Compare March 26, 2026 18:30
@ReenigneArcher ReenigneArcher force-pushed the fix/linux/migrate-to-qt-tray branch 3 times, most recently from be38d26 to 246b2e1 Compare March 28, 2026 02:50
Add support for simulating notification clicks and routing D-Bus notification actions to callbacks.

- Export tray_simulate_notification_click() in tray.h and provide platform implementations: no-op stubs for macOS and Windows, and a working simulator for Linux.
- Introduce TrayNotificationHandler (src/tray_notification_handler.h) to handle org.freedesktop.Notifications ActionInvoked signals and invoke the stored callback when the "default" action is triggered.
- Integrate the handler into the Linux tray: create/connect a single handler per QApplication, store callback and notification ID before calling Notify, set up a fallback that connects QSystemTrayIcon::messageClicked when D-Bus is unavailable, and clean up/disconnect the handler on app destroy.
- Also connect QSystemTrayIcon::activated to popup the context menu on left/middle clicks (fixes missing menu on left-click).
- Add unit tests verifying left-click menu popup and that notification callbacks fire when simulated (tests call tray_simulate_notification_click()).

These changes ensure notification clicks are handled consistently for D-Bus-dispatched notifications and add a test hook for exercising the click behavior.
Expose tray_set_log_callback in the public API and implement it on Linux to forward Qt diagnostic messages to a user-provided callback (NULL restores default behavior). Add a Qt message handler and global callback state, and route qInstallMessageHandler accordingly; provide no-op stubs on macOS and Windows since Qt logging is not used there. Improve context-menu positioning by calculating a sensible popup point from the tray icon geometry (falling back to cursor position) and use it when showing menus. Defer D-Bus ActionInvoked connection via QTimer::singleShot to avoid QSocketNotifier warnings when the tray runs in a std::thread, and add a few related include adjustments and minor activation handling cleanup.
Detect Wayland sessions and improve context-menu placement by prioritizing tray icon geometry, then using QCursor on Xorg, and falling back to a screen-geometry heuristic on Wayland (inferring panel edge from full vs available geometry). Defer showing the menu with QTimer::singleShot(0) and call QApplication::setActiveWindow before popup() so pointer grabs and XGrabPointer behavior work reliably; avoid showing the menu if it's already visible. Also avoid clearing the tray icon by only setting it when the resolved QIcon is valid, preventing spurious "No Icon set" warnings.
Replace QApplication::setActiveWindow with menu->activateWindow() to give the menu X11 focus before popup() and clarify the comment. Include QPixmap and change icon resolution logic: when the icon string refers to an existing file, load a QPixmap and add it to a QIcon immediately (avoiding QIcon's lazy loading that leaves availableSizes() empty and can produce a blank tray icon with Qt6 SNI). Fall back to QIcon::fromTheme() when the file doesn't exist. Keep guarding against setting null icons.
Delete legacy CMake find modules for AppIndicator and LibNotify
Add SVG tray icon support and make Linux tray handling more robust:

- CMake: include icons/*.svg, link Qt Svg (Qt5/Qt6), and copy icon.svg to build dir.
- Add new icons/icon.svg asset.
- src/tray_linux.cpp: improve Wayland detection, calculate menu position with preferred position, derive screen anchor, retry popup logic, robust icon resolution (file, pixmap, themed), set application/desktop names, and fallback standard icon.
- tests/unit/test_tray.cpp: ensure test icons are copied into the test binary directory, add TestTrayIconSvgFile unit test.

These changes fix issues with blank tray icons (Qt/SNI) and unreliable menu placement on Wayland, and add SVG icon support across platforms.
Add a matrix dimension for Qt version and run builds for both Qt5 and Qt6 on Ubuntu. The build job name now includes the Qt version, and qt_version is set per matrix entry. Linux dependency installation is made conditional on QT_VERSION (installing Qt5 or Qt6 packages accordingly) and QT_VERSION is exported into the job environment. Split CMake configure and ninja build into separate steps, make test environment/platformtheme conditional, and append Qt version to artifact names and codecov flags. Update README to document Qt5 and Qt6 package installation commands for supported distros.
Replace QCoreApplication::applicationDisplayName and setApplicationDisplayName with QGuiApplication equivalents in src/tray_linux.cpp. This ensures the GUI-specific API is used when initializing the tray's display name (from tooltip or default), avoiding misuse of QCoreApplication for GUI-only display name operations.
Make CMakeLists usable as a subproject: detect top-level build (TRAY_IS_TOP_LEVEL) and gate BUILD_DOCS/BUILD_TESTS/BUILD_EXAMPLE on it. Don't override parent CMAKE_MODULE_PATH; append module path relative to current source dir. Centralize icon paths into TRAY_ICON_* variables, add tray_copy_default_icons() to copy icons at post-build, and install icons/headers. Use target_include_directories and expose compile definitions publicly for the library. Adjust Qt/Qt-version caching and other target properties.

Update tests/CMakeLists.txt to use CMAKE_CURRENT_SOURCE_DIR paths, reference the googletest directory relatively, force shared CRT on Windows earlier, link the test target against tray::tray, add icon copying for the test binary, and register the test with add_test.
Add a new API tray_set_app_info to provide application metadata (name, display name, desktop file) used by the Linux/Qt backend and add no-op stubs for macOS and Windows. Improve Qt integration on Linux: add run_on_qt_thread helper, make g_exit_pending atomic, ensure all Qt GUI and teardown operations run on the Qt thread, and handle external event loops safely. Update notification/D-Bus handling and move tray updates, menu popup and simulated notification clicks onto the Qt thread to avoid cross-thread warnings. Also remove the QUIET flag from find_package(Qt6) in CMake and add necessary includes (atomic, utility, QThread).
Only perform install steps when the project is top-level by wrapping install commands in if(TRAY_IS_TOP_LEVEL). Also normalize to lowercase install() and remove the duplicated target name (was INSTALL(TARGETS tray tray ...)). This prevents unintended installs when the project is used as a subdirectory while preserving header and icon installations.
Add detection for reachable Wayland/X11 endpoints and fall back to the minimal QPA if none are present. Introduce QDir include and helper functions has_wayland_display_endpoint(), has_x11_display_endpoint(), and should_force_headless_qpa_fallback() to check WAYLAND_DISPLAY and DISPLAY (including XDG_RUNTIME_DIR sockets and /tmp/.X11-unix/X<n> sockets, as well as remote/TCP displays). If QT_QPA_PLATFORM is unset and no local display endpoints are found, set QT_QPA_PLATFORM=minimal before creating QApplication and emit a log via g_log_cb. This prevents trying to use GUI QPAs when no local display is reachable.
Add automatic discovery of a Wayland display socket when WAYLAND_DISPLAY is not set. Introduce discover_wayland_display_name() to scan XDG_RUNTIME_DIR for wayland-* entries (preferring wayland-0) and try_autodiscover_wayland_display() to export the found name via qputenv. Call the autodiscovery at tray initialization and emit a log message on success. Also include QStringList header required for the new code.
@ReenigneArcher ReenigneArcher force-pushed the fix/linux/migrate-to-qt-tray branch from 246b2e1 to ff76d0e Compare March 29, 2026 03:23
Add the missing standard library header to src/tray_windows.c to ensure declarations for libc functions used in the file are available and to prevent implicit-declaration warnings or build errors.
@sonarqubecloud
Copy link
Copy Markdown

@ReenigneArcher ReenigneArcher merged commit d05166f into master Mar 29, 2026
18 of 19 checks passed
@ReenigneArcher ReenigneArcher deleted the fix/linux/migrate-to-qt-tray branch March 29, 2026 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant