From 2037a211644ab16a132a2602d8179a8187e16f30 Mon Sep 17 00:00:00 2001 From: Peter Fern Date: Sun, 10 Mar 2024 13:38:09 +1100 Subject: [PATCH] feat(power): Wire up low/critical power commands --- cmd/hyprpanel/host.go | 9 +++ internal/dbus/power.go | 104 +++++++++++++++++++-------- proto/hyprpanel/event/v1/event.pb.go | 34 +++++---- proto/hyprpanel/event/v1/event.proto | 1 + 4 files changed, 105 insertions(+), 43 deletions(-) diff --git a/cmd/hyprpanel/host.go b/cmd/hyprpanel/host.go index 9f4e4ee..a424221 100644 --- a/cmd/hyprpanel/host.go +++ b/cmd/hyprpanel/host.go @@ -315,6 +315,15 @@ func (h *host) watch(hyprEvtCh <-chan *eventv1.Event) { if err := h.BrightnessAdjust(data.DevName, data.Direction); err != nil { h.log.Warn(`Brightness adjustment failed`, `err`, err) } + case eventv1.EventKind_EVENT_KIND_EXEC: + cmd, err := eventv1.DataString(evt.Data) + if err != nil { + h.log.Warn(`Invalid event`, `evt`, evt) + continue + } + if err := h.Exec(cmd); err != nil { + h.log.Warn(`Exec failed`, `err`, err) + } default: for _, panel := range h.panels { panel.Notify(evt) diff --git a/internal/dbus/power.go b/internal/dbus/power.go index 92c1005..3e685bf 100644 --- a/internal/dbus/power.go +++ b/internal/dbus/power.go @@ -32,7 +32,9 @@ type power struct { displayDevicePath dbus.ObjectPath - cachePower map[string]*eventv1.PowerChangeValue + cachePower map[string]*eventv1.PowerChangeValue + levelLow bool + levelCritical bool eventCh chan *eventv1.Event signals chan *dbus.Signal @@ -40,7 +42,7 @@ type power struct { quitCh chan struct{} } -func (b *power) updatePower(objPath dbus.ObjectPath, props map[string]dbus.Variant) error { +func (p *power) updatePower(objPath dbus.ObjectPath, props map[string]dbus.Variant) error { name := filepath.Base(string(objPath)) if name == powerDisplayDevice { name = eventv1.PowerDefaultID @@ -49,12 +51,12 @@ func (b *power) updatePower(objPath dbus.ObjectPath, props map[string]dbus.Varia powerValue := &eventv1.PowerChangeValue{ Id: name, } - lastValue, ok := b.cachePower[name] + lastValue, ok := p.cachePower[name] if ok { proto.Merge(powerValue, lastValue) } else if !ok || props == nil { lastValue = &eventv1.PowerChangeValue{} - busObj := b.conn.Object(fdoUPowerName, objPath) + busObj := p.conn.Object(fdoUPowerName, objPath) call := busObj.Call(fdoPropertiesMethodGetAll, 0, fdoUPowerDeviceName) if call.Err != nil { return fmt.Errorf("failed getting power device properties: %w", call.Err) @@ -117,8 +119,46 @@ func (b *power) updatePower(objPath dbus.ObjectPath, props map[string]dbus.Varia return err } powerValue.Percentage = uint32(math.Round(val)) - if powerValue.Percentage <= b.cfg.LowPercent && powerValue.Percentage != lastValue.Percentage { - hudUpdate = true + if powerValue.Percentage <= p.cfg.LowPercent { + if powerValue.Percentage != lastValue.Percentage { + hudUpdate = true + + if !p.levelLow && (powerValue.State != eventv1.PowerState_POWER_STATE_CHARGING && powerValue.State != eventv1.PowerState_POWER_STATE_FULLY_CHARGED && powerValue.State != eventv1.PowerState_POWER_STATE_PENDING_CHARGE) { + p.levelLow = true + + evt, err := eventv1.NewString(eventv1.EventKind_EVENT_KIND_EXEC, p.cfg.LowCommand) + if err != nil { + return err + } + + select { + case <-p.quitCh: + return nil + case p.eventCh <- evt: + } + } + } + } else { + p.levelLow = false + } + + if powerValue.Percentage <= p.cfg.CriticalPercent { + if powerValue.Percentage != lastValue.Percentage && !p.levelCritical && (powerValue.State != eventv1.PowerState_POWER_STATE_CHARGING && powerValue.State != eventv1.PowerState_POWER_STATE_FULLY_CHARGED && powerValue.State != eventv1.PowerState_POWER_STATE_PENDING_CHARGE) { + p.levelCritical = true + + evt, err := eventv1.NewString(eventv1.EventKind_EVENT_KIND_EXEC, p.cfg.CriticalCommand) + if err != nil { + return err + } + + select { + case <-p.quitCh: + return nil + case p.eventCh <- evt: + } + } + } else { + p.levelCritical = false } case fdoUPowerDevicePropertyState, strcase.ToKebab(fdoUPowerDevicePropertyState): var val eventv1.PowerState @@ -159,24 +199,28 @@ func (b *power) updatePower(objPath dbus.ObjectPath, props map[string]dbus.Varia } } - b.cachePower[powerValue.Id] = powerValue + p.cachePower[powerValue.Id] = powerValue powerData, err := anypb.New(powerValue) if err != nil { return fmt.Errorf(`failed encodiung event data for power dev (%s): %w`, name, err) } - b.eventCh <- &eventv1.Event{ + select { + case <-p.quitCh: + return nil + case p.eventCh <- &eventv1.Event{ Kind: eventv1.EventKind_EVENT_KIND_DBUS_POWER_CHANGE, Data: powerData, + }: } - if !b.cfg.HudNotifications || !hudUpdate || powerValue.Type != eventv1.PowerType_POWER_TYPE_BATTERY { + if !p.cfg.HudNotifications || !hudUpdate || powerValue.Type != eventv1.PowerType_POWER_TYPE_BATTERY { return nil } select { - case <-b.readyCh: + case <-p.readyCh: default: return nil } @@ -220,67 +264,71 @@ func (b *power) updatePower(objPath dbus.ObjectPath, props map[string]dbus.Varia return err } - b.eventCh <- &eventv1.Event{ + select { + case <-p.quitCh: + return nil + case p.eventCh <- &eventv1.Event{ Kind: eventv1.EventKind_EVENT_KIND_HUD_NOTIFY, Data: hudData, + }: } return nil } -func (b *power) init() error { - busObj := b.conn.Object(fdoUPowerName, fdoUPowerPath) +func (p *power) init() error { + busObj := p.conn.Object(fdoUPowerName, fdoUPowerPath) call := busObj.Call(fdoUPowerMethodGetDisplayDevice, 0) if call.Err != nil { return fmt.Errorf("failed getting default power device: %w", call.Err) } - if err := call.Store(&b.displayDevicePath); err != nil { + if err := call.Store(&p.displayDevicePath); err != nil { return err } - deviceObj := b.conn.Object(fdoUPowerDeviceName, b.displayDevicePath) + deviceObj := p.conn.Object(fdoUPowerDeviceName, p.displayDevicePath) if err := deviceObj.AddMatchSignal(fdoPropertiesName, fdoPropertiesMemberPropertiesChanged).Err; err != nil { return err } - if err := b.updatePower(b.displayDevicePath, nil); err != nil { + if err := p.updatePower(p.displayDevicePath, nil); err != nil { return err } - close(b.readyCh) + close(p.readyCh) - go b.watch() + go p.watch() return nil } -func (b *power) watch() { +func (p *power) watch() { for { select { - case <-b.quitCh: + case <-p.quitCh: return default: select { - case <-b.quitCh: + case <-p.quitCh: return - case sig, ok := <-b.signals: + case sig, ok := <-p.signals: if !ok { return } switch sig.Name { case fdoPropertiesSignalPropertiesChanged: - if sig.Path != b.displayDevicePath { + if sig.Path != p.displayDevicePath { continue } if len(sig.Body) != 3 { - b.log.Warn(`Failed parsing DBUS PropertiesChanged body`, `body`, sig.Body) + p.log.Warn(`Failed parsing DBUS PropertiesChanged body`, `body`, sig.Body) continue } kind, ok := sig.Body[0].(string) if !ok { - b.log.Warn(`Failed asserting DBUS PropertiesChanged body kind`, `kind`, sig.Body[0]) + p.log.Warn(`Failed asserting DBUS PropertiesChanged body kind`, `kind`, sig.Body[0]) continue } if kind != fdoUPowerDeviceName { @@ -289,15 +337,15 @@ func (b *power) watch() { properties, ok := sig.Body[1].(map[string]dbus.Variant) if !ok { - b.log.Warn(`Failed asserting DBUS PropertiesChanged body properties`, `properties`, sig.Body[1]) + p.log.Warn(`Failed asserting DBUS PropertiesChanged body properties`, `properties`, sig.Body[1]) continue } if len(properties) == 0 { continue } - if err := b.updatePower(sig.Path, properties); err != nil { - b.log.Warn(`Failed polling power`, `path`, sig.Path, `err`, err) + if err := p.updatePower(sig.Path, properties); err != nil { + p.log.Warn(`Failed polling power`, `path`, sig.Path, `err`, err) continue } } diff --git a/proto/hyprpanel/event/v1/event.pb.go b/proto/hyprpanel/event/v1/event.pb.go index 604edb4..769bbf1 100644 --- a/proto/hyprpanel/event/v1/event.pb.go +++ b/proto/hyprpanel/event/v1/event.pb.go @@ -261,6 +261,7 @@ const ( EventKind_EVENT_KIND_HYPR_CREATEWORKSPACEV2 EventKind = 56 EventKind_EVENT_KIND_HYPR_DESTROYWORKSPACEV2 EventKind = 57 EventKind_EVENT_KIND_HYPR_WORKSPACEV2 EventKind = 58 + EventKind_EVENT_KIND_EXEC EventKind = 59 ) // Enum value maps for EventKind. @@ -324,6 +325,7 @@ var ( 56: "EVENT_KIND_HYPR_CREATEWORKSPACEV2", 57: "EVENT_KIND_HYPR_DESTROYWORKSPACEV2", 58: "EVENT_KIND_HYPR_WORKSPACEV2", + 59: "EVENT_KIND_EXEC", } EventKind_value = map[string]int32{ "EVENT_KIND_UNSPECIFIED": 0, @@ -384,6 +386,7 @@ var ( "EVENT_KIND_HYPR_CREATEWORKSPACEV2": 56, "EVENT_KIND_HYPR_DESTROYWORKSPACEV2": 57, "EVENT_KIND_HYPR_WORKSPACEV2": 58, + "EVENT_KIND_EXEC": 59, } ) @@ -3262,7 +3265,7 @@ var file_hyprpanel_event_v1_event_proto_rawDesc = []byte{ 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x48, 0x41, 0x52, 0x47, 0x45, 0x10, 0x05, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x4f, 0x57, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x49, 0x53, 0x43, 0x48, 0x41, 0x52, 0x47, 0x45, 0x10, 0x06, - 0x2a, 0xf1, 0x0f, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1a, + 0x2a, 0x86, 0x10, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x48, 0x59, 0x50, 0x52, 0x5f, 0x57, 0x4f, @@ -3389,20 +3392,21 @@ var file_hyprpanel_event_v1_event_proto_rawDesc = []byte{ 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x56, 0x32, 0x10, 0x39, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x48, 0x59, 0x50, 0x52, 0x5f, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, - 0x56, 0x32, 0x10, 0x3a, 0x42, 0xc9, 0x01, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x79, 0x70, - 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x42, - 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x39, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x64, 0x66, 0x2f, 0x68, 0x79, - 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x79, - 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x31, - 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x48, 0x45, 0x58, 0xaa, 0x02, - 0x12, 0x48, 0x79, 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12, 0x48, 0x79, 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5c, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1e, 0x48, 0x79, 0x70, 0x72, 0x70, - 0x61, 0x6e, 0x65, 0x6c, 0x5c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, - 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x48, 0x79, 0x70, 0x72, - 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x3a, 0x3a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x3a, 0x3a, 0x56, 0x31, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x56, 0x32, 0x10, 0x3a, 0x12, 0x13, 0x0a, 0x0f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x4b, 0x49, + 0x4e, 0x44, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x10, 0x3b, 0x42, 0xc9, 0x01, 0x0a, 0x16, 0x63, 0x6f, + 0x6d, 0x2e, 0x68, 0x79, 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, + 0x64, 0x66, 0x2f, 0x68, 0x79, 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x68, 0x79, 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2f, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, + 0x48, 0x45, 0x58, 0xaa, 0x02, 0x12, 0x48, 0x79, 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x2e, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12, 0x48, 0x79, 0x70, 0x72, 0x70, + 0x61, 0x6e, 0x65, 0x6c, 0x5c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1e, + 0x48, 0x79, 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x5c, + 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, + 0x14, 0x48, 0x79, 0x70, 0x72, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x3a, 0x3a, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/hyprpanel/event/v1/event.proto b/proto/hyprpanel/event/v1/event.proto index 384bad1..ebe7412 100644 --- a/proto/hyprpanel/event/v1/event.proto +++ b/proto/hyprpanel/event/v1/event.proto @@ -93,6 +93,7 @@ enum EventKind { EVENT_KIND_HYPR_CREATEWORKSPACEV2 = 56; EVENT_KIND_HYPR_DESTROYWORKSPACEV2 = 57; EVENT_KIND_HYPR_WORKSPACEV2 = 58; + EVENT_KIND_EXEC = 59; } message HyprWorkspaceV2Value {