Skip to content

Add support for rate #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 40 additions & 9 deletions cmd_apply.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package main

import (
"bytes"
"errors"
"fmt"
"html/template"
"os"
"os/exec"
"strings"
"time"
)

type CmdApply struct{}
Expand All @@ -25,35 +28,63 @@ func (cmd CmdApply) Usage() string {
}

func ApplyRule(outputs Outputs, rule Rule) error {
var cmds []*exec.Cmd
var cmds commands
var err error

switch {
case rule.ConfigureSingle != "" || len(rule.ConfigureRow) > 0 || len(rule.ConfigureColumn) > 0:
cmds, err = BuildCommandOutputRow(rule, outputs)
case rule.ConfigureCommand != "":
cmds = []*exec.Cmd{exec.Command("sh", "-c", rule.ConfigureCommand)}
cmds = commands{command{"sh", "-c", rule.ConfigureCommand}}
default:
return fmt.Errorf("no output configuration for rule %v", rule.Name)
}

after := append(globalOpts.cfg.ExecuteAfter, rule.ExecuteAfter...)
if len(after) > 0 {
for _, cmd := range after {
cmds = append(cmds, exec.Command("sh", "-c", cmd))
if err != nil {
return err
}

foundError := false
for _, cmd := range cmds {
for i := 0; i < 4; i++ {
err = RunCommand(cmd.Cmd())
if err == nil {
break
}
fmt.Fprintf(os.Stderr, "executing command for rule %v failed: %v\n", rule.Name, err)

dur := time.Millisecond * 500 * time.Duration(i)
fmt.Fprintf(os.Stderr, "trying again in %s", dur)
time.Sleep(dur)
}
if err != nil {
fmt.Fprint(os.Stderr, "failed after 3 retries")
foundError = true
}
}
if foundError {
return nil // Dont run ExecuteAfter if xrandr commands failed
}

newOutputs, err := DetectOutputs()
if err != nil {
return err
}
for _, cmd := range cmds {
err = RunCommand(cmd)

after := append(globalOpts.cfg.ExecuteAfter, rule.ExecuteAfter...)
for _, cmd := range after {
buf := &bytes.Buffer{}
tmpl, err := template.New("titleTest").Parse(cmd)
if err != nil {
fmt.Fprintf(os.Stderr, "executing template for rule %v failed: %v\n", rule.Name, err)
continue
}
tmpl.Execute(buf, newOutputs)
err = RunCommand(exec.Command("sh", "-c", buf.String()))
if err != nil {
fmt.Fprintf(os.Stderr, "executing command for rule %v failed: %v\n", rule.Name, err)
}
}

return nil
}

Expand Down
65 changes: 9 additions & 56 deletions cmd_watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ func (cmd CmdWatch) Execute(args []string) (err error) {
var eventReceived bool

var lastRule Rule
var lastOutputs Outputs
for {
if !disablePoll {
var outputs Outputs
Expand All @@ -117,53 +116,6 @@ func (cmd CmdWatch) Execute(args []string) (err error) {
return fmt.Errorf("detecting outputs: %w", err)
}

// disable outputs which have a changed display
var off Outputs
for _, o := range outputs {
for _, last := range lastOutputs {
if o.Name != last.Name {
continue
}

if last.Active() && !o.Active() {
V(" output %v: monitor not active any more, disabling", o.Name)
off = append(off, o)
continue
}

if o.Active() && o.MonitorID != last.MonitorID {
V(" output %v: monitor has changed, disabling", o.Name)
off = append(off, o)
continue
}
}
}

if len(off) > 0 {
V("disable %d outputs", len(off))

cmd, err := DisableOutputs(off)
if err != nil {
return fmt.Errorf("disabling outputs: %w", err)
}

// forget the last rule set, something has changed for sure
lastRule = Rule{}

err = RunCommand(cmd)
if err != nil {
fmt.Fprintf(os.Stderr, "error disabling: %v\n", err)
}

// refresh outputs again
outputs, err = GetOutputs()
if err != nil {
return fmt.Errorf("detecting outputs after disabling: %w", err)
}

V("new outputs after disable: %v", outputs)
}

rule, err := MatchRules(globalOpts.cfg.Rules, outputs)
if err != nil {
return fmt.Errorf("matching rules: %w", err)
Expand All @@ -173,6 +125,15 @@ func (cmd CmdWatch) Execute(args []string) (err error) {
V("outputs: %v", outputs)
V("new rule found: %v", rule.Name)

// Disable old rules outputs if they are not in current active rules outputs.
diff := rule.OutputsDiff(lastRule)
if len(diff) > 0 {
err = RunCommand(DisableOutputs(diff))
if err != nil {
fmt.Fprintf(os.Stderr, "error disabling: %v", err)
}
}

err = ApplyRule(outputs, rule)
if err != nil {
return fmt.Errorf("applying rules: %w", err)
Expand All @@ -185,15 +146,7 @@ func (cmd CmdWatch) Execute(args []string) (err error) {
disablePoll = true
backoffCh = time.After(time.Duration(globalOpts.Pause) * time.Second)
}

// refresh outputs for next cycle
outputs, err = GetOutputs()
if err != nil {
return fmt.Errorf("refreshing outputs: %w", err)
}
}

lastOutputs = outputs
}

select {
Expand Down
6 changes: 3 additions & 3 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Config struct {
OnFailure []string `yaml:"on_failure"`
}

// xdgConfigDir returns the config directory according to the xdg standard, see
// xdgConfigDir returns the config directory according to the xdg standard, see.
// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html.
func xdgConfigDir() string {
if dir := os.Getenv("XDG_CONFIG_HOME"); dir != "" {
Expand All @@ -37,7 +37,8 @@ func openConfigFile(name string) (io.ReadCloser, error) {
os.Getenv("GROBI_CONFIG"),
filepath.Join(xdgConfigDir(), "grobi.conf"),
filepath.Join(os.Getenv("HOME"), ".grobi.conf"),
"/etc/xdg/grobi.conf"} {
"/etc/xdg/grobi.conf",
} {
if filename != "" {
if f, err := os.Open(filename); err == nil {
V("reading config from %v\n", filename)
Expand Down Expand Up @@ -81,7 +82,6 @@ func readConfig(name string) (Config, error) {

// Valid returns an error if the config is invalid, ie a pattern is malformed.
func (cfg Config) Valid() error {

for _, rule := range cfg.Rules {
for _, list := range [][]string{rule.OutputsPresent, rule.OutputsAbsent, rule.OutputsConnected, rule.OutputsDisconnected} {
for _, pat := range list {
Expand Down
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ func RunCommand(cmd *exec.Cmd) error {
return cmd.Run()
}

var globalOpts = GlobalOptions{}
var parser = flags.NewParser(&globalOpts, flags.Default)
var (
globalOpts = GlobalOptions{}
parser = flags.NewParser(&globalOpts, flags.Default)
)

func V(s string, data ...interface{}) {
if globalOpts.Verbose && globalOpts.log == nil {
Expand Down
Loading