Skip to content

Split TrayApp into a separate composenativetray-app module (#418) - #419

Merged
kdroidFilter merged 8 commits into
masterfrom
feat/split-trayapp-module
Aug 15, 2026
Merged

Split TrayApp into a separate composenativetray-app module (#418)#419
kdroidFilter merged 8 commits into
masterfrom
feat/split-trayapp-module

Conversation

@kdroidFilter

@kdroidFilter kdroidFilter commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Fixes #418.

Splits the single composenativetray artifact so apps that only need a basic system tray icon no longer pull in the decorated-window-tao windowing backend. Basic Tray is now a top-level composable and works in any Compose Desktop application { } — no NucleusApplicationScope required.

What changed

  • New :tray-app module (dev.nucleusframework:composenativetray-app) holds TrayApp and its TrayAppState / TrayWindowDismissMode / animation helper. It owns the nucleus.application + nucleus.decorated-window-tao dependencies.
  • Core composenativetray keeps the Tray / menu DSL and native tray implementation, and drops both nucleus.application and decorated-window-tao. Tray(...) is a regular @Composable (no Nucleus receiver).
  • Positioning helpers (getTrayPosition, getTrayWindowPosition, TrayPosition) live in :tray-app next to the Tao backend they need. Core only records raw tray-icon clicks (TrayClickTracker).
  • NativeTray is public so tray-app can drive it directly. No change to the Tray / TrayApp call-site API beyond dropping the unused Nucleus receiver on Tray.
  • Bump Nucleus 2.0.32.4.4.
  • README updated: two artifacts, Tray works in application { }, TrayApp still requires nucleusApplication { }.

Consumer impact

  • Basic tray users: same composenativetray coordinate, now lighter — no Nucleus application JAR, and Tray can be called from Compose Desktop application { }.
  • TrayApp users: add implementation("dev.nucleusframework:composenativetray-app:<version>"). Positioning helpers move to package dev.nucleusframework.composenativetray.trayapp.

Verification

  • composenativetray, :tray-app and :demo compile; ktlint + core tests pass.
  • ./gradlew :dependencies --configuration jvmRuntimeClasspath confirms nucleus-application and decorated-window-tao are absent from the core runtime classpath (core-runtime + darkmode-detector remain).
  • Existing release workflow (publishAndReleaseToMavenCentral) publishes both modules with no change, since the unqualified task runs in the root and every subproject that registers it.

Move TrayApp and its state/dismiss-mode/animation helpers into a new
:tray-app module, published as composenativetray-app, so apps that only
need a basic tray icon no longer pull in the decorated-window-tao
windowing backend.

- Core (composenativetray) keeps the Tray/menu API and native tray impl
  unchanged, and drops its direct decorated-window-tao dependency.
- TrayScreenGeometry is now windowing-agnostic (injectable scale/work-area
  providers with fallbacks); tray-app installs the Tao-backed geometry.
- NativeTray and TrayScreenGeometry are now public (shared engine used by
  both modules); the public Tray / TrayApp API is unchanged.
- Bump Nucleus to 2.0.5.
- README: document the two artifacts and correct the snippets to the
  current nucleusApplication / SingleInstanceRestoreEffect API.
… screen fallback

Addresses the code-review findings on the module split.

- Move TrayScreenGeometry + all popup positioning (getTrayWindowPosition /
  getTrayWindowPositionForInstance, corner detection, persistence) into
  :tray-app, where the Tao backend is always present. The core artifact no
  longer fabricates a 1920x1080 screen when no windowing backend is available:
  the native tray managers just record the raw tray-icon click, and tray-app
  resolves the corner + window position against real Tao geometry. macOS native
  status-item queries are reached through typed MacTrayInitializer wrappers so
  the JNI bridge stays internal.
- Move TrayApp/TrayAppState/TrayWindowDismissMode and friends to package
  dev.nucleusframework.composenativetray.trayapp so no package is split across
  the two published JARs (unblocks JPMS module-path consumers).
- tray-app: declare nucleus.application as api (it is TrayApp's receiver type).
- Align the tray-app log timestamp format with the core formatter.
- README: document the trayapp package and that getTrayWindowPosition lives in
  composenativetray-app; getTrayPosition stays in core.

Consequence: getTrayPosition() on Linux, when used without composenativetray-app,
returns the desktop-environment default corner instead of a click-derived one.
getTrayPosition() and the TrayPosition enum now live in composenativetray-app
(package ...trayapp), next to the popup positioning they feed, so the core
artifact exposes no tray-corner / positioning API at all. The native
tray-region queries are reached through typed wrappers
(WindowsTrayInitializer.notificationIconsRegion, MacTrayInitializer.statusItemRegion)
so the JNI bridges stay internal to core.

Core's TrayPosition.kt is reduced to the raw click tracker (TrayClickTracker +
TrayClickPoint) and renamed TrayClickTracker.kt. Demos and README updated for
the new package. This also removes the Linux core-only degradation: getTrayPosition
now always has Tao geometry available in tray-app.
Comment thread build.gradle.kts Outdated
…sent

Align :tray-app with 9194bd0 (master): the unconditional signAllPublications()
predates the merge and broke publishToMavenLocal without a signatory.
@kdroidFilter
kdroidFilter merged commit 2e093a5 into master Aug 15, 2026
5 checks passed
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.

[Enhancement] Separate TrayApp from the core Compose Tray

2 participants