//nolint:revive package v2 import ( "reflect" "slices" "dario.cat/mergo" ) var ignoreTypes = []reflect.Type{ // Ignore primary as we always overwrite primary when set. reflect.TypeOf(Primary(true)), // Ignore DisplayPort as we should always use the original value. reflect.TypeOf(DisplayPort("")), // Ignore MPID as we should always use the original value. reflect.TypeOf(MPID("")), } // Merge B into A and return a new copy. // // We assume A is a valid display configuration, i.e. details all displays that are present // on the node, and only apply configuration from B when it matches displays in A. // // When a display is present in both A and B, the displays will be merged in the // result - see Display.Merge(Display) for more detail. If a display is present in A but // not in B, it will be added to the result without changes. If a display is present in B, // but not A it will not be added to the result. // // The Layout from B will be merged into A. Only displays in B also present in A will be // respected. See Layout.Merge(Layout) for more detail. func (a *DisplayConfig) Merge(b *DisplayConfig) (*DisplayConfig, error) { if b == nil { return a, nil } result := a.DeepCopy() displays, err := result.Displays.Merge(b.Displays) if err != nil { return nil, err } result.Displays = displays // Merge DPMS, see DPMS.Merge(DPMS) for more detail. dpms, err := result.DPMS.Merge(b.DPMS) if err != nil { return nil, err } result.DPMS = dpms // Merge Layout, see Layout.Merge(Layout) for more detail. result.Layout = result.Layout.Merge(b.Layout) return result, nil } func (a Displays) Merge(b Displays) (Displays, error) { result := a.DeepCopy() // Merge displays that are present in both A and B // see Display.Merge(Display) for more detail. for _, bDisplay := range b { if aDisplay := result.FindByDisplayPort(bDisplay.DisplayPort); aDisplay != nil { display, err := aDisplay.Merge(bDisplay) if err != nil { return nil, err } result.UpdateDisplay(*display) } } result = mergePrimaries(result, b) return result, nil } // If primary has been set in B for a display also present in A, // the primary display will be updated in A to that in B. func mergePrimaries(a, b Displays) Displays { result := a.DeepCopy() // check if primary is set in B for any of the displays in A var primary DisplayPort for _, aDisplay := range result { dp := aDisplay.DisplayPort if bDisplay := b.FindByDisplayPort(dp); bDisplay != nil { if bDisplay.IsPrimary() { primary = dp break } } } // if we found a new primary, update the result if primary != "" { for _, display := range result { if display.DisplayPort == primary { display.SetPrimary(true) } else if display.IsPrimary() { display.SetPrimary(false) } result.UpdateDisplay(display) } } return result } // Merge Display B into Display A and return a new copy. // // When a value is present in B set it in A, otherwise use the value from A. // // Input device mappings in b will always replace the mappings in a if the mappings // in B are not empty, i.e. mappings in B are not appended to those in A. func (a *Display) Merge(b Display) (*Display, error) { base := a.DeepCopy() overlay := b.DeepCopy() if err := mergo.Merge( base, overlay, mergo.WithOverride, mergo.WithTransformers(t), ); err != nil { return nil, err } return base, nil } func (a *DPMS) Merge(b *DPMS) (*DPMS, error) { if a == nil { return b, nil } else if b == nil { return a, nil } base := a.DeepCopy() overlay := b.DeepCopy() if err := mergo.Merge( base, overlay, mergo.WithOverride, mergo.WithTransformers(t), ); err != nil { return nil, err } return base, nil } // Merge Layout B into Layout A and return a new copy. // // For each display in B present in A, we append to the result respecting the order // in B. For the remaining display in A not present in B, we append to the result // respecting the order in A. func (a Layout) Merge(b Layout) Layout { if len(a) == 0 { return a } result := Layout{} // add each display in B that is present in A, respecting its order in B for _, dp := range b { if slices.Contains(a, dp) { result = append(result, dp) } } // add the remaining displays from A that were not in B, respecting its order in A for _, dp := range a { if !slices.Contains(result, dp) { result = append(result, dp) } } return result }