package xrandr import ( "encoding/json" "errors" "fmt" "os/exec" "strings" ) type Arrangement map[string]*DisplayArrangement type DisplayArrangement struct { Off bool `json:"off,omitempty"` Primary bool `json:"primary,omitempty"` Position *Position `json:"position,omitempty"` Resolution *Resolution `json:"resolution,omitempty"` Rate float64 `json:"rate,omitempty"` Rotation Rotation `json:"rotation,omitempty"` Reflection Reflection `json:"reflection,omitempty"` } func (a *DisplayArrangement) Equivalent(b *DisplayArrangement) bool { return a.Off == b.Off && a.Primary == b.Primary && a.Position.Equivalent(b.Position) && a.Resolution.Equivalent(b.Resolution) && a.Rate == b.Rate && a.Rotation == b.Rotation && a.Reflection == b.Reflection } func (a *Arrangement) xrandr() string { b := new(strings.Builder) b.WriteString("xrandr") for port, display := range *a { b.WriteString(fmt.Sprintf(" --output %s", port)) if display.Off { b.WriteString(" --off") continue } if display.Primary { b.WriteString(" --primary") } b.WriteString(" --preferred") if display.Position != nil { b.WriteString(fmt.Sprintf(" --pos %dx%d", display.Position.X, display.Position.Y)) } if display.Resolution != nil { b.WriteString(fmt.Sprintf(" --mode %dx%d", display.Resolution.Width, display.Resolution.Height)) } if display.Rate > 0 { b.WriteString(fmt.Sprintf(" --rate %g", display.Rate)) } b.WriteString(fmt.Sprintf(" --rotate %s", display.Rotation)) b.WriteString(fmt.Sprintf(" --reflect %s", display.Reflection.xrandr())) } return b.String() } func (a *Arrangement) Apply() error { cmd := strings.Split(a.xrandr(), " ") xrandr := exec.Command(cmd[0], cmd[1:]...) if err := xrandr.Start(); err != nil { return err } if err := xrandr.Wait(); err != nil { return err } if !xrandr.ProcessState.Success() { return errors.New("xrandr could not apply display arrangement") } return nil } func (a *Arrangement) Display(port string) *DisplayArrangement { return (*a)[port] } func (a *Arrangement) String() string { data, _ := json.MarshalIndent(a, "", "\t") return string(data) } func (a *DisplayArrangement) String() string { data, _ := json.MarshalIndent(a, "", "\t") return string(data) }