diff --git a/doc/grobi.conf b/doc/grobi.conf index ff700cc..c751edb 100644 --- a/doc/grobi.conf +++ b/doc/grobi.conf @@ -98,6 +98,25 @@ rules: execute_after: - xautolock -disable + # Setup mirror + # Set DP-2 (External) as primary + # And mirror on the laptop + - name: Mirror + outputs_connected: [eDP-1, DP-2] + outputs_present: [eDP-1, DP-2] + + configure_row: + - DP-2 + + configure_mirror: [DP-2, eDP-1] + primary: DP-2 + + # Additional commands can be specified per rule, in this case we make sure + # that xautolock is enabled and locks the screen after a while. + execute_after: + - xautolock -enable + + # If none of the rules above match, it's a good idea to have a fallback rule # which enables an output device that is always present, so you can debug # what's going on. diff --git a/randr.go b/randr.go index b6de378..8398dd2 100644 --- a/randr.go +++ b/randr.go @@ -498,6 +498,8 @@ func BuildCommandOutputRow(rule Rule, current Outputs) ([]*exec.Cmd, error) { outputs = []string{rule.ConfigureSingle} case len(rule.ConfigureRow) > 0: outputs = rule.ConfigureRow + case len(rule.ConfigureMirror) == 1: + return nil, errors.New("mirror must have 2 or more displays") default: return nil, errors.New("empty monitor row configuration") } @@ -507,6 +509,11 @@ func BuildCommandOutputRow(rule Rule, current Outputs) ([]*exec.Cmd, error) { command := "xrandr" enableOutputArgs := [][]string{} + mirrornames := make(map[string]struct{}) + for _, name := range rule.ConfigureMirror { + mirrornames[name] = struct{}{} + } + active := make(map[string]struct{}) var lastOutput = "" for i, output := range outputs { @@ -552,10 +559,13 @@ func BuildCommandOutputRow(rule Rule, current Outputs) ([]*exec.Cmd, error) { } disableOutputArgs := [][]string{} - // honour disable_order if present for _, name := range rule.DisableOrder { if _, ok := disableOutputs[name]; ok { + // Do not disable a mirrored output + if _, mirrored := mirrornames[name]; mirrored { + continue + } args := []string{"--output", name, "--off"} disableOutputArgs = append(disableOutputArgs, args) @@ -565,10 +575,24 @@ func BuildCommandOutputRow(rule Rule, current Outputs) ([]*exec.Cmd, error) { // collect remaining outputs to be disabled for name := range disableOutputs { + // Do not disable a mirrored output + if _, mirrored := mirrornames[name]; mirrored { + continue + } args := []string{"--output", name, "--off"} disableOutputArgs = append(disableOutputArgs, args) } + mirrorOutputArgs := [][]string{} + if len(rule.ConfigureMirror) > 1 { + m := rule.ConfigureMirror[0] + for _, name := range rule.ConfigureMirror[1:] { + mirrorOutputArgs = append(mirrorOutputArgs, + []string{"--output", name, "--auto", "--same-as", m}, + ) + } + } + // enable/disable all monitors in one call to xrandr if rule.Atomic { V("using one atomic call to xrandr\n") @@ -579,6 +603,9 @@ func BuildCommandOutputRow(rule Rule, current Outputs) ([]*exec.Cmd, error) { for _, enableArgs := range enableOutputArgs { args = append(args, enableArgs...) } + for _, mirrorArgs := range mirrorOutputArgs { + args = append(args, mirrorArgs...) + } cmd := exec.Command(command, args...) return []*exec.Cmd{cmd}, nil } @@ -609,6 +636,12 @@ func BuildCommandOutputRow(rule Rule, current Outputs) ([]*exec.Cmd, error) { cmds = append(cmds, exec.Command(command, args...)) } + if len(mirrorOutputArgs) > 0 { + args := []string{} + args = append(args, mirrorOutputArgs[0]...) + cmds = append(cmds, exec.Command(command, args...)) + } + return cmds, nil } diff --git a/rule.go b/rule.go index 5a235f7..fe8b357 100644 --- a/rule.go +++ b/rule.go @@ -11,6 +11,7 @@ type Rule struct { ConfigureRow []string `yaml:"configure_row"` ConfigureSingle string `yaml:"configure_single"` + ConfigureMirror []string `yaml:"configure_mirror"` ConfigureCommand string `yaml:"configure_command"` Primary string `yaml:"primary"`