Skip to content

feat: add native macOS tray renderer#1440

Merged
shm11C3 merged 1 commit into
developfrom
feat/1401-macos-renderer
May 3, 2026
Merged

feat: add native macOS tray renderer#1440
shm11C3 merged 1 commit into
developfrom
feat/1401-macos-renderer

Conversation

@shm11C3

@shm11C3 shm11C3 commented May 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add a TraySurface abstraction so platform-specific tray renderers can be swapped independently.
  • Implement a native AppKit-backed macOS tray renderer for feat: live hardware metrics in system tray / menu bar (Stats-like widget) #1401 while keeping the existing Tauri tray path for other OSes.
  • Render CPU/GPU values with native icons, keep the app logo visible in the tray, and tint the SVG logo through AppKit template rendering so it follows NSColor::labelColor().
  • Add focused tests for tray frame icon metadata, empty metric frames, macOS attributed title layout, and logo template behavior.

Related Issues

Refs #1401

Type of Change

  • Bug fix (fix/ branch)
  • New feature (feat/ branch)
  • Refactoring (refactor/ branch)
  • Documentation (docs/ branch)
  • Dependencies update
  • Other (chore/ branch)

Screenshots / Videos

N/A

Test Plan

  • Manual testing
  • Unit tests

Commands run:

cargo test -p hardware_visualizer tray::
cargo clippy -p hardware_visualizer --all-targets

Checklist

  • Self-reviewed the code
  • Linting and formatting pass (npm run lint && npm run format / cargo tauri-lint && cargo tauri-fmt)
  • Tests pass (npm test / cargo tauri-test)
  • No new warnings or errors

Summary by CodeRabbit

Release Notes

  • New Features
    • Tray interface now displays metric icons and values alongside status information
    • Enhanced macOS tray integration with native system appearance and interactions
    • Visual state indicators for metrics with color-based differentiation (normal, warning, critical)

Introduce a TraySurface abstraction so macOS can use an AppKit-backed status item while other platforms keep the Tauri tray implementation.

Render CPU/GPU metrics with native icons, keep the app logo visible, and tint the SVG logo as a template image. Add focused tray widget and macOS surface tests.

Validation: cargo test -p hardware_visualizer tray::; cargo clippy -p hardware_visualizer --all-targets.
@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR introduces a TraySurface abstraction layer for platform-specific tray UI handling. A native macOS implementation using AppKit (NSStatusItem with attributed titles displaying metric icons and values) replaces direct tray icon management, while a Tauri fallback maintains backward compatibility. The tray adapter is refactored to use this abstraction, and TrayFrame is extended with metric item rendering metadata.

Changes

Tray Surface Abstraction & macOS Native Implementation

Layer / File(s) Summary
Dependencies
src-tauri/Cargo.toml
Added macOS-specific dependencies: objc2, objc2-app-kit, and objc2-foundation with AppKit/Foundation feature flags for native Objective-C interop.
Data Shape
src-tauri/src/tray/widget.rs
Extended TrayFrame with new items: Vec<TrayFrameItem> field; added TrayFrameItem and TrayMetricIcon structs to carry per-metric UI metadata (icon labels, symbol names, formatted values, and metric state). Updated build_frame to populate items with metric icons and state-based coloring.
Abstraction Layer
src-tauri/src/tray/mod.rs, src-tauri/src/tray/surface/mod.rs
Introduced TraySurface trait with platform-agnostic apply_frame(&self, frame: &TrayFrame) and close(&self) methods. Created factory function create(app: &tauri::App) to conditionally instantiate platform-specific implementations as Box<dyn TraySurface>.
macOS Implementation
src-tauri/src/tray/surface/macos.rs
Implemented MacosTraySurface using AppKit (NSStatusItem, custom NSView subclass). Constructs attributed title with SVG app logo, per-metric symbol images (or fallback text), and metric value ranges colored by MetricState. Enforces main-thread execution via run_on_main_thread for all AppKit mutations. Defines Objective-C runtime classes for menu item targets and the tray view with mouse event handlers (left-click restores window, right-click opens menu). Includes safe Drop behavior to prevent unsafe off-thread deallocation.
Tauri Fallback Implementation
src-tauri/src/tray/surface/tauri_surface.rs
Implemented TauriTraySurface using Tauri's built-in tray API, maintaining the previous behavior with "Open" and "Quit" menu items. Registers event handlers for menu and tray icon interactions; apply_frame updates title/tooltip from TrayFrame.
Adapter Integration
src-tauri/src/adapters/tray.rs
Refactored TrayAdapter to accept a TraySurface abstraction instead of directly managing TrayIcon. Removed tray construction logic from setup; instead creates surface via factory and passes it to the widget updater. Updated updater loop to call surface.apply_frame(&next_frame) and surface.close(). Exposed restore_main_window and spawn_quit as pub(crate) for use by platform implementations.
Tests & Validation
src-tauri/src/tray/widget.rs, src-tauri/src/tray/surface/macos.rs
Updated TrayFrame tests to assert items content, icon metadata, and title formatting. Added macOS tests validating attributed-title construction, metric coloring by state, and app-logo rendering. Verified behavior when metrics are unavailable.

Sequence Diagram

sequenceDiagram
    participant Widget as Tray Widget
    participant Adapter as TrayAdapter
    participant Surface as TraySurface (Abstract)
    participant Platform as Platform Impl
    participant Native as macOS AppKit / Tauri API

    Widget->>Adapter: next_frame (TrayFrame with metrics)
    Adapter->>Surface: apply_frame(&frame)
    
    alt macOS Implementation
        Surface->>Platform: MacosTraySurface::apply_frame
        Platform->>Platform: Build attributed title<br/>(logo + metric icons)
        Platform->>Native: run_on_main_thread()
        Native->>Native: Update NSStatusItem title/tooltip
        Native-->>Platform: Scheduled & executed
    else Tauri Fallback
        Surface->>Platform: TauriTraySurface::apply_frame
        Platform->>Native: Update tray icon title/tooltip
        Native-->>Platform: Updated
    end
    
    Platform-->>Surface: Frame applied
    Surface-->>Adapter: Complete
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly Related PRs

  • feat: add tray metrics widget #1439: Modifies the same tray subsystem files (adapters/tray.rs, tray/mod.rs, tray/widget.rs)—this PR added tray metrics widget, while the current PR introduces the TraySurface abstraction with native macOS and Tauri implementations.
  • feat(app): system tray adapter with Open / Quit menu (#1422) #1425: Implements the initial Tauri-backed TrayAdapter and TrayIcon setup; the current PR refactors that adapter to use the new TraySurface abstraction, moving the same tray logic into platform-specific implementations.

Suggested Labels

rust

Poem

🐰 Hopped through AppKit's garden maze,
Surface abstraction sets ablaze,
Metrics twinkle, icons glow,
Platform-proof now, don't you know! ✨🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a native macOS tray renderer, which aligns with the primary objective of implementing AppKit-backed macOS tray rendering.
Description check ✅ Passed The description covers all critical sections: a clear summary of changes, related issue reference, type of change selection, test plan with commands run, and a mostly complete checklist with explanations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/1401-macos-renderer

Review rate limit: 4/5 reviews remaining, refill in 12 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added dependencies Pull requests that update a dependency file configuration feature hardviz_tauri labels May 2, 2026
@github-actions

github-actions Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor

Rust Tauri Coverage Report

Coverage Details
Filename                                     Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_tests/commands/background_image_test.rs          39                 0   100.00%           6                 0   100.00%          21                 0   100.00%           0                 0         -
_tests/commands/settings_test.rs                 219                 0   100.00%          18                 0   100.00%         162                 0   100.00%           0                 0         -
adapters/tray.rs                                 152               152     0.00%          15                15     0.00%         104               104     0.00%           0                 0         -
adapters/window.rs                               254                69    72.83%          21                 8    61.90%         195                47    75.90%           0                 0         -
app/startup.rs                                   188                87    53.72%          10                 3    70.00%         114                58    49.12%           0                 0         -
commands/background_image.rs                      22                 7    68.18%          11                 5    54.55%          19                 7    63.16%           0                 0         -
commands/hardware.rs                              62                62     0.00%          20                20     0.00%          68                68     0.00%           0                 0         -
commands/settings.rs                             578               578     0.00%         102               102     0.00%         497               497     0.00%           0                 0         -
commands/system.rs                                21                21     0.00%          10                10     0.00%          20                20     0.00%           0                 0         -
commands/ui.rs                                    17                17     0.00%           2                 2     0.00%          13                13     0.00%           0                 0         -
commands/updater.rs                               97                97     0.00%          15                15     0.00%          66                66     0.00%           0                 0         -
enums/error.rs                                   115                10    91.30%           9                 1    88.89%          99                10    89.90%           0                 0         -
enums/hardware.rs                                194                 7    96.39%          16                 1    93.75%         120                 6    95.00%           0                 0         -
enums/settings.rs                                425                16    96.24%          26                 2    92.31%         289                10    96.54%           0                 0         -
infrastructure/database/migration.rs              66                 1    98.48%          10                 0   100.00%          86                 0   100.00%           0                 0         -
lib.rs                                           205               205     0.00%           5                 5     0.00%         124               124     0.00%           0                 0         -
lifecycle.rs                                     227               178    21.59%          29                25    13.79%         160               137    14.37%           0                 0         -
main.rs                                            3                 3     0.00%           1                 1     0.00%           3                 3     0.00%           0                 0         -
models/hardware.rs                               375                83    77.87%          31                12    61.29%         275               100    63.64%           0                 0         -
models/hardware_archive.rs                         8                 0   100.00%           2                 0   100.00%          10                 0   100.00%           0                 0         -
models/settings.rs                               283                 0   100.00%          16                 0   100.00%         246                 0   100.00%           0                 0         -
services/background_image_service.rs             165                96    41.82%          16                10    37.50%          93                59    36.56%           0                 0         -
services/gpu_service.rs                           56                56     0.00%          11                11     0.00%          43                43     0.00%           0                 0         -
services/hardware_service.rs                      85                85     0.00%           4                 4     0.00%          51                51     0.00%           0                 0         -
services/language_service.rs                     101                 0   100.00%          18                 0   100.00%          57                 0   100.00%           0                 0         -
services/memory_service.rs                        12                12     0.00%           3                 3     0.00%           7                 7     0.00%           0                 0         -
services/motherboard_service.rs                   12                12     0.00%           3                 3     0.00%           7                 7     0.00%           0                 0         -
services/network_service.rs                       14                14     0.00%           1                 1     0.00%           8                 8     0.00%           0                 0         -
services/settings_service.rs                     321               143    55.45%          31                13    58.06%         269               130    51.67%           0                 0         -
services/system_service.rs                        22                22     0.00%           2                 2     0.00%          12                12     0.00%           0                 0         -
services/ui_service.rs                            45                45     0.00%           8                 8     0.00%          36                36     0.00%           0                 0         -
tray/surface/mod.rs                                8                 8     0.00%           2                 2     0.00%           5                 5     0.00%           0                 0         -
tray/surface/tauri_surface.rs                     80                80     0.00%           6                 6     0.00%          48                48     0.00%           0                 0         -
tray/widget.rs                                   539                27    94.99%          49                 3    93.88%         494                26    94.74%           0                 0         -
utils/color.rs                                    66                 1    98.48%           4                 0   100.00%          26                 0   100.00%           0                 0         -
utils/file.rs                                    224                 5    97.77%          14                 0   100.00%         144                 4    97.22%           0                 0         -
utils/formatter.rs                                55                 0   100.00%           5                 0   100.00%          39                 0   100.00%           0                 0         -
utils/logger.rs                                   71                71     0.00%           1                 1     0.00%          38                38     0.00%           0                 0         -
utils/tauri.rs                                   138                 0   100.00%          17                 0   100.00%          82                 0   100.00%           0                 0         -
workers/mod.rs                                    40                40     0.00%           2                 2     0.00%          24                24     0.00%           0                 0         -
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TOTAL                                           5604              2310    58.78%         572               296    48.25%        4174              1768    57.64%           0                 0         -

@shm11C3 shm11C3 marked this pull request as ready for review May 2, 2026 23:40
Copilot AI review requested due to automatic review settings May 2, 2026 23:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a platform-swappable tray rendering abstraction to support a native AppKit-backed macOS tray/widget surface while keeping the existing Tauri tray implementation for non-macOS platforms.

Changes:

  • Introduces TraySurface and moves the existing Tauri tray implementation behind it (non-macOS).
  • Implements a native macOS NSStatusItem surface that renders an attributed title with a template-tinted app logo + metric icons/values.
  • Extends tray frame modeling to include per-metric icon metadata and adds focused unit tests.

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src-tauri/src/tray/widget.rs Extends TrayFrame with items (icon/value/state) and updates frame building + tests.
src-tauri/src/tray/surface/mod.rs Defines TraySurface trait and factory selecting macOS vs non-macOS implementation.
src-tauri/src/tray/surface/tauri_surface.rs New non-macOS tray surface using Tauri tray APIs (menu + title/tooltip updates).
src-tauri/src/tray/surface/macos.rs New native AppKit tray surface using NSStatusItem + attributed title rendering and tests.
src-tauri/src/tray/mod.rs Exposes new tray::surface module.
src-tauri/src/adapters/tray.rs Refactors adapter to drive a TraySurface instead of owning TrayIcon directly.
src-tauri/Cargo.toml Adds macOS-only objc2* dependencies required for AppKit implementation.
assets/hv-icon-outline.svg Adds outline logo SVG used for template-tinted menu bar rendering.
Cargo.lock Locks new macOS dependency graph.

Comment thread src-tauri/src/tray/surface/macos.rs
Comment thread src-tauri/src/tray/widget.rs
Comment thread src-tauri/src/tray/surface/tauri_surface.rs
Comment thread src-tauri/src/tray/surface/macos.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src-tauri/src/tray/widget.rs (1)

306-324: Use valid SF Symbol names for metric icons. The symbols "cpu" and "display" are not valid SF Symbols in any macOS version; "thermometer" requires macOS 13.0+. The code gracefully falls back to text labels when symbols are unavailable, but for better UX, consider using alternative valid symbols: "cpu.fill" or "gear" for CPU, "display" could use "desktopcomputer" or "macbook", and "thermometer" is valid but dependent on macOS minimum version support. The fallback mechanism ensures no runtime errors, but using valid symbol names will display icons instead of text labels.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src-tauri/src/tray/widget.rs` around lines 306 - 324, Replace invalid SF
Symbol names in metric_icon_config so macOS shows icons instead of fallback
text: for TrayMetric::Cpu set macos_symbol_name to a valid symbol such as
"cpu.fill" or "gear"; for TrayMetric::Gpu set macos_symbol_name to a valid
symbol such as "desktopcomputer" or "macbook"; for TrayMetric::Temp either keep
"thermometer" only if macOS deployment target supports it or use a more widely
available alternative like "thermometer.sun" or "thermometer.medium". Update the
macos_symbol_name fields on the TrayMetricIcon values in metric_icon_config
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src-tauri/src/tray/widget.rs`:
- Around line 306-324: Replace invalid SF Symbol names in metric_icon_config so
macOS shows icons instead of fallback text: for TrayMetric::Cpu set
macos_symbol_name to a valid symbol such as "cpu.fill" or "gear"; for
TrayMetric::Gpu set macos_symbol_name to a valid symbol such as
"desktopcomputer" or "macbook"; for TrayMetric::Temp either keep "thermometer"
only if macOS deployment target supports it or use a more widely available
alternative like "thermometer.sun" or "thermometer.medium". Update the
macos_symbol_name fields on the TrayMetricIcon values in metric_icon_config
accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: ef9299bf-03d5-4314-ac83-75ca20115034

📥 Commits

Reviewing files that changed from the base of the PR and between 811cd45 and b8f3709.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • assets/hv-icon-outline.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • src-tauri/Cargo.toml
  • src-tauri/src/adapters/tray.rs
  • src-tauri/src/tray/mod.rs
  • src-tauri/src/tray/surface/macos.rs
  • src-tauri/src/tray/surface/mod.rs
  • src-tauri/src/tray/surface/tauri_surface.rs
  • src-tauri/src/tray/widget.rs

@shm11C3 shm11C3 merged commit 9fa520f into develop May 3, 2026
47 checks passed
@shm11C3 shm11C3 deleted the feat/1401-macos-renderer branch May 3, 2026 01:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

configuration dependencies Pull requests that update a dependency file feature hardviz_tauri

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants