Skip to content

Commit

Permalink
feat(power): Wire up low/critical power commands
Browse files Browse the repository at this point in the history
  • Loading branch information
pdf committed Mar 10, 2024
1 parent 730e65d commit 2037a21
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 43 deletions.
9 changes: 9 additions & 0 deletions cmd/hyprpanel/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
104 changes: 76 additions & 28 deletions internal/dbus/power.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,17 @@ 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
readyCh chan 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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}
}
Expand Down
34 changes: 19 additions & 15 deletions proto/hyprpanel/event/v1/event.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions proto/hyprpanel/event/v1/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 2037a21

Please sign in to comment.