147 lines
3.3 KiB
Go
147 lines
3.3 KiB
Go
package monitor
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
|
|
"led-controller/config"
|
|
)
|
|
|
|
type Event int
|
|
|
|
const (
|
|
DisplayOn Event = iota
|
|
DisplayOff
|
|
)
|
|
|
|
type Monitor struct {
|
|
cfg *config.Config
|
|
events chan<- Event
|
|
}
|
|
|
|
func New(cfg *config.Config, events chan<- Event) (*Monitor, error) {
|
|
return &Monitor{cfg: cfg, events: events}, nil
|
|
}
|
|
|
|
func (m *Monitor) Run(ctx context.Context) {
|
|
method := m.cfg.Monitor.Method
|
|
|
|
if method == "screensaver" || method == "all" {
|
|
go m.watchScreenSaver(ctx)
|
|
}
|
|
if method == "logind" || method == "all" {
|
|
go m.watchLogind(ctx)
|
|
}
|
|
|
|
<-ctx.Done()
|
|
}
|
|
|
|
// watchScreenSaver listens on the session bus for org.freedesktop.ScreenSaver.ActiveChanged
|
|
// This covers GNOME, KDE, XFCE, and other freedesktop-compliant DEs.
|
|
func (m *Monitor) watchScreenSaver(ctx context.Context) {
|
|
conn, err := dbus.ConnectSessionBus()
|
|
if err != nil {
|
|
log.Printf("screensaver monitor: cannot connect to session bus: %v", err)
|
|
return
|
|
}
|
|
defer conn.Close()
|
|
|
|
// Match both the freedesktop and GNOME screensaver interfaces
|
|
rules := []string{
|
|
"type='signal',interface='org.freedesktop.ScreenSaver',member='ActiveChanged'",
|
|
"type='signal',interface='org.gnome.ScreenSaver',member='ActiveChanged'",
|
|
}
|
|
|
|
for _, rule := range rules {
|
|
call := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule)
|
|
if call.Err != nil {
|
|
log.Printf("screensaver monitor: AddMatch failed for %q: %v", rule, call.Err)
|
|
}
|
|
}
|
|
|
|
sigCh := make(chan *dbus.Signal, 16)
|
|
conn.Signal(sigCh)
|
|
|
|
log.Println("screensaver monitor: listening for ActiveChanged signals")
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case sig := <-sigCh:
|
|
if sig == nil {
|
|
return
|
|
}
|
|
if sig.Name == "org.freedesktop.ScreenSaver.ActiveChanged" ||
|
|
sig.Name == "org.gnome.ScreenSaver.ActiveChanged" {
|
|
if len(sig.Body) < 1 {
|
|
continue
|
|
}
|
|
active, ok := sig.Body[0].(bool)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if active {
|
|
log.Println("screensaver monitor: screen locked/blanked")
|
|
m.events <- DisplayOff
|
|
} else {
|
|
log.Println("screensaver monitor: screen unlocked/unblanked")
|
|
m.events <- DisplayOn
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// watchLogind listens on the system bus for org.freedesktop.login1.Manager.PrepareForSleep.
|
|
// This catches system suspend/resume events.
|
|
func (m *Monitor) watchLogind(ctx context.Context) {
|
|
conn, err := dbus.ConnectSystemBus()
|
|
if err != nil {
|
|
log.Printf("logind monitor: cannot connect to system bus: %v", err)
|
|
return
|
|
}
|
|
defer conn.Close()
|
|
|
|
rule := "type='signal',interface='org.freedesktop.login1.Manager',member='PrepareForSleep'"
|
|
call := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule)
|
|
if call.Err != nil {
|
|
log.Printf("logind monitor: AddMatch failed: %v", call.Err)
|
|
return
|
|
}
|
|
|
|
sigCh := make(chan *dbus.Signal, 16)
|
|
conn.Signal(sigCh)
|
|
|
|
log.Println("logind monitor: listening for PrepareForSleep signals")
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case sig := <-sigCh:
|
|
if sig == nil {
|
|
return
|
|
}
|
|
if sig.Name == "org.freedesktop.login1.Manager.PrepareForSleep" {
|
|
if len(sig.Body) < 1 {
|
|
continue
|
|
}
|
|
preparing, ok := sig.Body[0].(bool)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if preparing {
|
|
log.Println("logind monitor: system preparing to sleep")
|
|
m.events <- DisplayOff
|
|
} else {
|
|
log.Println("logind monitor: system woke up")
|
|
m.events <- DisplayOn
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|