Desktop tray functionality and controls#538
Open
epicleafies wants to merge 9 commits intobitcoin-core:qt6from
Open
Desktop tray functionality and controls#538epicleafies wants to merge 9 commits intobitcoin-core:qt6from
epicleafies wants to merge 9 commits intobitcoin-core:qt6from
Conversation
Contributor
Author
|
Needs testing on Windows and Mac. Some of the behavior is OS dependent. |
Member
|
Please rebase. |
342e670 to
3629563
Compare
johnny9
reviewed
Mar 29, 2026
Collaborator
There was a problem hiding this comment.
I like the settings options but lets try to use the QML SystemTrayIcon instead of implementing the platform-specific DBus notification apis. These will only work on linux platforms.
One problem with these tray icons is that Qt doesn't support the native versions on all platforms and this means we'll need to link Widgets in order to implement this on platforms that don't have native support which I think includes Windows
QSystemTrayIcon requires QApplication (not QGuiApplication), so switch the main binary and the unit test runner to QApplication and add Qt6::Widgets to the build. On Linux, Qt may route tray icon ownership through the DBus StatusNotifierItem protocol, so add a WITH_DBUS option (on by default for non-Windows/macOS/Android targets) that conditionally finds and links Qt6::DBus. Wire in the two new unit test translation units for the tray models so the test binary picks them up.
Exposes three boolean settings — showTrayIcon, minimizeToTray, and minimizeOnClose — persisted via QSettings using the legacy Bitcoin Qt keys (fHideTrayIcon, fMinimizeToTray, fMinimizeOnClose) for settings file compatibility. On non-desktop platforms all three are forced to false and ignore writes. Cascade logic ensures that disabling showTrayIcon also clears the dependent minimizeToTray and minimizeOnClose so the UI and persisted state stay consistent. Two composite helpers, shouldHideToTrayOnMinimize() and shouldMinimizeWindowOnClose(), provide the combined conditions needed by main.qml. A second constructor accepting explicit default values enables deterministic unit testing without touching the on-disk QSettings.
Wraps QSystemTrayIcon with the extra machinery needed for reliable cross-platform operation: - Show is deferred to the first event-loop iteration so DBus/SNI is ready on Linux before we call QSystemTrayIcon::show(). - Up to four retries with increasing delays (100–400 ms) handle slow SNI host initialization on some compositors. - A native QMenu with Show/Quit actions is installed before the first show() to satisfy AppIndicator/SNI ownership requirements. - On Linux an XDG-compliant icon theme is written to a temporary directory so the system can resolve the icon by name, avoiding rendering artefacts from direct pixmap injection. - Dark-mode support: on non-macOS platforms updateIcon() inverts pixel luminance when isDark is true; on macOS setIsMask(true) is used so the system composites the icon correctly in both modes. Signals restoreRequested, quitRequested, and contextMenuRequested decouple tray-event handling from the controller itself so QML can connect freely.
The existing Setting component had no way to render a visually disabled row while keeping it present in the layout — setting Qt's enabled:false also suppresses the item entirely from focus and hit-testing in ways that break parent layouts. Add a disabled property (distinct from enabled) with a matching DISABLED state that renders the header and description in a muted, theme-aware color. Mouse-area handlers are guarded on !root.disabled so hover/active states cannot fire while the row is disabled. A stateDescriptionColor property is threaded through to the inner SettingItem so the description text follows the same color transitions.
Adds a new settings page reachable from Node Settings → Window Behavior (desktop only) with three toggles backed by desktopWindowBehaviorModel: - Show tray icon: always enabled on desktop - Minimize to tray: enabled only when show tray icon is on - Minimize on close: enabled only when show tray icon is on The two dependent switches use the new Setting.disabled property to appear visually greyed out while showTrayIcon is off. A QML unit test verifies the enabled/disabled transitions for each switch based on platform and model state.
Instantiate DesktopWindowBehaviorModel and DesktopTrayIconController in QmlGuiMain and expose them to QML via rootContext. The tray icon is shown on startup only in desktop app-mode when showTrayIcon is persisted as true; if the system tray turns out to be unsupported after all retries, supportedChanged feeds back into the model so the setting is cleared rather than left in an inconsistent state. Switch the entry point from QGuiApplication to QApplication, required by QSystemTrayIcon. Remove duplicate common/system.h and common/args.h includes that were present in bitcoin.cpp. Honor -resetguisettings by clearing the three window-behavior QSettings keys before the models read their initial values. In main.qml: - onClosing either hides the window (if minimizeOnClose is set) or requests a node shutdown, replacing the previous unconditional quit. - onVisibilityChanged tracks the previous visibility in m_prevVisibility to distinguish a genuine user minimize from the Hidden→Minimized transition that showNormal() emits internally; without this guard the window would immediately re-hide after a tray-icon restore. - Connections to desktopTrayIconController handle restore, quit, and context-menu requests from the tray. - A Menu provides Show/Hide and Quit items for the tray context menu. - A Binding keeps the controller's isDark in sync with Theme.dark so the tray icon recolors automatically when the user switches themes.
Add qml_test_tray.py, an end-to-end functional test that navigates to Settings → Window Behavior, asserts the three switches are present and have the expected default states, exercises toggle round-trips, and verifies that back navigation and re-opening the page work correctly. Wire it into the GitHub Actions functional-tests job.
3629563 to
25accd4
Compare
The original implementation included Linux-specific code paths to work around StatusNotifierItem/AppIndicator behaviour: deferred show() with exponential-backoff retries, XDG icon theme file management, and a separate setIcon() entry point that wrote pixmaps into ~/.local/share/icons/hicolor/. These workarounds are platform-specific and do not belong in a cross-platform tray implementation. Replace with a straightforward QSystemTrayIcon wrapper: show()/hide() are called synchronously, icon theming is handled through updateIcon() as before (with macOS mask support), and the context menu is registered without AppIndicator-specific ordering constraints. Update unit tests to cover the simplified interface using googletest (matching the project's current test framework) instead of QtTest, and drop the Linux-only XDG icon theme tests that tested the removed code.
The WITH_DBUS option was introduced to link Qt6::DBus on Linux for the StatusNotifierItem tray workarounds, which have now been removed from DesktopTrayIconController. Qt's platform plugin handles any necessary D-Bus communication internally; no explicit DBus linkage is needed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Added window behavior as a new option in settings. #513
Added window behavior page, allows the user to configure if the tray is visible, behavior on minimization and behavior on closing.
Tray icon matches dark and light mode in the app.
Tray icon gives option to show or quit when clicked on.
Added unit, qml and functional tests.