Skip to content

Live monitoring of tray items in the open popup#2

Open
heath-toby wants to merge 1 commit into
destructatron:mainfrom
heath-toby:feat/live-monitoring
Open

Live monitoring of tray items in the open popup#2
heath-toby wants to merge 1 commit into
destructatron:mainfrom
heath-toby:feat/live-monitoring

Conversation

@heath-toby

Copy link
Copy Markdown

Summary

Adds end-to-end live updates for every tray module item while the WayTray popup is open. Previously the popup only reflected state captured when the window was first opened — changes from SNI apps (Bluetooth state, NM network state, etc.) and from internal modules (volume sliders, brightness) were invisible until the popup was closed and reopened.

Three concerns addressed

  • Worker-thread signal consumer (client). The previous approach awaited zbus signal streams directly under glib::spawn_future_local, which silently failed to deliver ItemsChanged events on this stack (the cross-runtime waker didn't reliably re-enter GLib's main loop). The new daemon_proxy::spawn_change_listener owns the zbus subscription on a dedicated tokio runtime in its own thread and forwards each notification through an async_channel. The main GTK thread just recv().awaits on that channel — no executor coupling, no foreign-waker plumbing.

  • AT-SPI Description gating (client). update_item_if_changed used to gate both accessible::Property::Label and accessible::Property::Description on label_changed. For SNI items like Blueman whose title is the constant string "blueman" while their tooltip ("Bluetooth Active""Bluetooth Disabled") tracks the state, this meant Orca never heard new state because the gate never fired. Description is now gated independently on tooltip_changed.

  • IconAccessibleDesc fallback (daemon). nm-applet (and other Ayatana SNI apps) publish their human-readable state in IconAccessibleDesc and emit no NewToolTip. The daemon now reads IconAccessibleDesc as a fallback when ToolTip is missing or unhelpful, and re-fetches the tooltip on every NewIcon signal so apps that update the description alongside the icon stay current.

Test plan

  • Open popup, leave it open, adjust system volume via up/down arrows on the pipewire item — label updates live.
  • Open popup, leave it open, change brightness via the brightness item — label updates live.
  • Open popup, leave it open, toggle Bluetooth via `bluetoothctl power off; bluetoothctl power on` — Blueman item's tooltip ("Bluetooth Active" / "Bluetooth Disabled") updates live; Orca reads the new state when re-querying.
  • Open popup with nm-applet on Wi-Fi, leave it open, walk to change signal strength — nm-applet description ("Wi-Fi network connection "X" (45%)") updates live.
  • Run with `RUST_LOG=info waytray` and confirm `Signal listener: subscribed to ItemsChanged` and `Live updates: main-thread consumer started` appear, and `Live updates: ItemsChanged notification received` fires on changes.

🤖 Generated with Claude Code

Adds end-to-end live updates for every tray module item while the WayTray
popup is open. Previously the popup only reflected state captured when the
window was first opened — changes from SNI apps (Bluetooth state, NM
network state, etc.) and from internal modules (volume sliders, brightness)
were invisible until the popup was closed and reopened.

Three concerns are addressed:

* Worker-thread signal consumer (client). The previous approach awaited
  zbus signal streams directly under `glib::spawn_future_local`, which
  silently failed to deliver `ItemsChanged` events on this stack (the
  cross-runtime waker didn't reliably re-enter GLib's main loop). The new
  `daemon_proxy::spawn_change_listener` owns the zbus subscription on a
  dedicated tokio runtime in its own thread and forwards each notification
  through an `async_channel`. The main GTK thread just `recv().await`s on
  that channel — no executor coupling, no foreign-waker plumbing.

* AT-SPI Description gating (client). `update_item_if_changed` used to
  gate both `accessible::Property::Label` and
  `accessible::Property::Description` on `label_changed`. For SNI items
  like Blueman whose title is the constant string "blueman" while their
  tooltip ("Bluetooth Active" → "Bluetooth Disabled") tracks the state,
  this meant Orca never heard new state because the gate never fired.
  Description is now gated independently on `tooltip_changed`.

* IconAccessibleDesc fallback (daemon). nm-applet (and other Ayatana SNI
  apps) publish their human-readable state in `IconAccessibleDesc` and
  emit no `NewToolTip`. The daemon now reads `IconAccessibleDesc` as a
  fallback when `ToolTip` is missing or unhelpful, and re-fetches the
  tooltip on every `NewIcon` signal so apps that update the description
  alongside the icon stay current.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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