Skip to content

fix: tray icons duplicating and disappearing after session restore#2117

Closed
Dimariqe wants to merge 1 commit intoAvengeMedia:masterfrom
Dimariqe:fix/icons-system-tray-disappeared
Closed

fix: tray icons duplicating and disappearing after session restore#2117
Dimariqe wants to merge 1 commit intoAvengeMedia:masterfrom
Dimariqe:fix/icons-system-tray-disappeared

Conversation

@Dimariqe
Copy link
Copy Markdown

Problem

After resume from suspend (or forced session restore via Hyprland),
some tray icons disappear. Apps that don't detect a StatusNotifierWatcher
restart don't re-register their SNI items, leaving the tray empty.

Additionally, a TrayRecoveryService that scans DBus for unregistered
SNI items after resume could produce duplicate icons because apps
may register their SNI item either via their well-known name
(com.example.AppName/StatusNotifierItem) or via their connection ID
(:1.49/StatusNotifierItem), and the old dedup logic didn't account
for this equivalence.

Root causes

  1. Directional blind spot — the well-known name scan and the
    connection-ID scan each only checked their own form against the
    registered items list. If an app registered as :1.49, the
    well-known-name section would still try to register
    com.example.AppName, and vice versa.

  2. Case-sensitive SNI Id comparison — some apps report their SNI
    Id property in a different case than their well-known name
    (e.g. "exampleapp" vs "com.example.ExampleApp/...").
    grep -qF never matched, so the fallback dedup check was silently
    skipped every time.

Solution

Add TrayRecoveryService — a singleton that fires 3 seconds after
resume and scans DBus for SNI items that need re-registration.

Key design decisions:

  • Unified REGISTERED_CONN_IDS set built upfront by resolving
    every currently registered item (regardless of whether it was
    registered as a well-known name or a connection ID) to its canonical
    :1.xxx connection ID. This is the single source of truth used by
    both scan sections.
  • Well-known name section first checks REGISTERED_CONN_IDS via
    the name's connection ID before probing — skips apps already covered
    by a connection-ID registration.
  • After registering via well-known name, REGISTERED_CONN_IDS is
    updated immediately so the connection-ID section running next won't
    probe the same app again in the same recovery pass.
  • Connection-ID section uses REGISTERED_CONN_IDS as its primary
    gate, with a case-insensitive SNI Id string match as a secondary
    fallback inside each parallel subshell.
  • Single busctl snapshot (BUSCTL_OUT) is taken once and reused
    across both sections, replacing two redundant dbus-send ListNames
    calls.

Add TrayRecoveryService singleton that re-registers lost tray icons
after resume from suspend via a bash DBus scan.

The service resolves every registered SNI item (both well-known names
and :1.xxx connection IDs) to a canonical connection ID, building a
unified REGISTERED_CONN_IDS set before either scan section runs. This
prevents duplicates in both directions:

- If an app registered via well-known name, the connection-ID section
  skips its :1.xxx entry.
- If an app registered via connection ID, the well-known-name section
  skips its well-known name (checked through REGISTERED_CONN_IDS).
- After successfully registering via well-known name, REGISTERED_CONN_IDS
  is updated immediately so the connection-ID section won't probe the
  same app in the same run.

A single busctl snapshot (BUSCTL_OUT) is reused across both sections,
replacing redundant dbus-send ListNames calls. The SNI Id dedup check
inside the connection-ID subshells is now case-insensitive (-i flag)
as a secondary fallback.
@bbedward
Copy link
Copy Markdown
Collaborator

This is nice, though I think we could just integrate it into DMS server, and not need any additional QML for it. That might be a better approach since it's already hooked in to everything.

@Dimariqe Dimariqe closed this Mar 31, 2026
@Dimariqe
Copy link
Copy Markdown
Author

I'll be back with a Go implementation.

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.

2 participants