mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-08 23:02:05 -04:00
* fix: add TrayRecoveryService with bidirectional SNI dedup (Go server)
Add TrayRecoveryService manager that re-registers lost tray icons after
resume from suspend via native DBus scanning in the Go server.
The service resolves every registered SNI item (both well-known names and
:1.xxx connection IDs) to a canonical connection ID, building a unified
registeredConnIDs 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 registeredConnIDs).
- After successfully registering via well-known name, registeredConnIDs
is updated immediately so the connection-ID section won't probe the
same app in the same run.
A startup scan (3 s delay) covers the common case where the DMS process
is killed during suspend and restarted by systemd (Type=dbus), so the
loginctl PrepareForSleep watcher alone is not sufficient. The startup
scan is harmless on a normal boot — it finds all items already registered
and exits early.
Go port of quickshell commit 1470aa3.
* fix: 'interface{}' can be replaced by 'any'
* TrayRecoveryService: Remove objPath parameter from registerSNI
94 lines
1.9 KiB
Go
94 lines
1.9 KiB
Go
package trayrecovery
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/loginctl"
|
|
"github.com/godbus/dbus/v5"
|
|
)
|
|
|
|
const resumeDelay = 3 * time.Second
|
|
|
|
type Manager struct {
|
|
conn *dbus.Conn
|
|
stopChan chan struct{}
|
|
wg sync.WaitGroup
|
|
}
|
|
|
|
func NewManager() (*Manager, error) {
|
|
conn, err := dbus.ConnectSessionBus()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to connect to session bus: %w", err)
|
|
}
|
|
|
|
m := &Manager{
|
|
conn: conn,
|
|
stopChan: make(chan struct{}),
|
|
}
|
|
|
|
// Run a startup scan after a delay — covers the case where the process
|
|
// was killed during suspend and restarted by systemd (Type=dbus).
|
|
// The fresh process never sees the PrepareForSleep true→false transition,
|
|
// so the loginctl watcher alone is not enough.
|
|
go m.scheduleRecovery()
|
|
|
|
return m, nil
|
|
}
|
|
|
|
// WatchLoginctl subscribes to loginctl session state changes and triggers
|
|
// tray recovery after resume from suspend (PrepareForSleep false transition).
|
|
// This handles the case where the process survives suspend.
|
|
func (m *Manager) WatchLoginctl(lm *loginctl.Manager) {
|
|
ch := lm.Subscribe("tray-recovery")
|
|
m.wg.Add(1)
|
|
go func() {
|
|
defer m.wg.Done()
|
|
defer lm.Unsubscribe("tray-recovery")
|
|
|
|
wasSleeping := false
|
|
for {
|
|
select {
|
|
case <-m.stopChan:
|
|
return
|
|
case state, ok := <-ch:
|
|
if !ok {
|
|
return
|
|
}
|
|
if state.PreparingForSleep {
|
|
wasSleeping = true
|
|
continue
|
|
}
|
|
if wasSleeping {
|
|
wasSleeping = false
|
|
go m.scheduleRecovery()
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (m *Manager) scheduleRecovery() {
|
|
select {
|
|
case <-time.After(resumeDelay):
|
|
m.recoverTrayItems()
|
|
case <-m.stopChan:
|
|
}
|
|
}
|
|
|
|
func (m *Manager) Close() {
|
|
select {
|
|
case <-m.stopChan:
|
|
return
|
|
default:
|
|
close(m.stopChan)
|
|
}
|
|
m.wg.Wait()
|
|
if m.conn != nil {
|
|
m.conn.Close()
|
|
}
|
|
log.Info("TrayRecovery manager closed")
|
|
}
|