package xrandr import ( "fmt" "slices" "maps" "edge-infra.dev/pkg/sds/display/displaymanager/applier/xorg/command" "edge-infra.dev/pkg/sds/display/displaymanager/applier/xorg/command/runner" "edge-infra.dev/pkg/sds/lib/xorg" ) const xrandrPath = "/usr/bin/xrandr" const ( outputFlag = "--output" modeFlag = "--mode" rotateFlag = "--rotate" primaryFlag = "--primary" posFlag = "--pos" rightOfFlag = "--right-of" ) // Command is able to build an Xrandr command to configure displays and run it. type Command interface { command.Command SetOutputMode(outputID xorg.OutputID, mode string) SetOutputRotation(outputID xorg.OutputID, rotation string) SetOutputAsPrimary(outputID xorg.OutputID) SetOutputPosition(outputID xorg.OutputID, xPos, yPos int) SetOutputRightOf(outputID, relativeTo xorg.OutputID) } // NewXrandrCommand returns a new xrandr.Command implementation. func NewXrandrCommand(cmdRunner runner.Runner) Command { return &xrandrCmd{ cmdRunner: cmdRunner, displayArgs: displayArgs{}, } } // Map of output IDs to the display's xrandr arguments type displayArgs map[xorg.OutputID][]string func (o displayArgs) Args() []string { args := []string{} // iterate over the sorted keys for consistent output outputIDs := slices.Collect(maps.Keys(o)) slices.Sort(outputIDs) for _, outputID := range outputIDs { args = append(args, outputFlag) args = append(args, outputID.String()) args = append(args, o[outputID]...) } return args } type xrandrCmd struct { cmdRunner runner.Runner displayArgs } func (x *xrandrCmd) Path() string { return xrandrPath } func (x *xrandrCmd) Run() error { if len(x.displayArgs) == 0 { return nil } return x.cmdRunner.Run(xrandrPath, x.displayArgs.Args()...) } func (x *xrandrCmd) SetOutputMode(outputID xorg.OutputID, mode string) { // e.g. --mode 1920x1080 x.displayArgs[outputID] = append(x.displayArgs[outputID], modeFlag, mode) } func (x *xrandrCmd) SetOutputRotation(outputID xorg.OutputID, rotation string) { // e.g. --orientation normal x.displayArgs[outputID] = append(x.displayArgs[outputID], rotateFlag, rotation) } func (x *xrandrCmd) SetOutputAsPrimary(outputID xorg.OutputID) { // e.g. --primary x.displayArgs[outputID] = append(x.displayArgs[outputID], primaryFlag) } func (x *xrandrCmd) SetOutputPosition(outputID xorg.OutputID, xPos, yPos int) { // e.g. --pos 0x0 x.displayArgs[outputID] = append(x.displayArgs[outputID], posFlag, fmt.Sprintf("%dx%d", xPos, yPos)) } func (x *xrandrCmd) SetOutputRightOf(outputID, relativeTo xorg.OutputID) { // e.g. --right-of DP1 x.displayArgs[outputID] = append(x.displayArgs[outputID], rightOfFlag, relativeTo.String()) }