package display

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/godbus/dbus"
	sysdisplay "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.display"
	inputdevices "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.inputdevices"
	ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus"
	login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1"
	gio "github.com/linuxdeepin/go-gir/gio-2.0"
	"github.com/linuxdeepin/go-lib/dbusutil"
	"github.com/linuxdeepin/go-lib/gsettings"
	"github.com/linuxdeepin/go-lib/log"
	"github.com/linuxdeepin/go-lib/xdg/basedir"
	x "github.com/linuxdeepin/go-x11-client"
	"github.com/linuxdeepin/go-x11-client/ext/randr"
	"github.com/linuxdeepin/startdde/display/brightness"
)

const (
	DisplayModeCustom uint8 = iota
	DisplayModeMirror
	DisplayModeExtend
	DisplayModeOnlyOne
	DisplayModeUnknown
)

// DisplayModeInvalid 无效的模式
const DisplayModeInvalid uint8 = 0

const (
	// 1：自动旋转；即未主动调用 SetRotation() 接口（由内部触发）发生的旋转操作，如根据重力传感器自动设定旋转方向
	RotationFinishModeAuto uint8 = iota + 1
	// 2：手动旋转；即主动调用 SetRotation() 接口完成旋转，如控制中心下拉框方式旋转屏幕
	RotationFinishModeManual
)

const (
	sensorProxyInterface       = "com.deepin.SensorProxy"
	sensorProxyPath            = "/com/deepin/SensorProxy"
	sensorProxySignalName      = "RotationValueChanged"
	sensorProxySignal          = "com.deepin.SensorProxy.RotationValueChanged"
	sensorProxyGetScreenStatus = "com.deepin.SensorProxy.GetScreenStatus"
)

const (
	gsSchemaDisplay  = "com.deepin.dde.display"
	gsKeyDisplayMode = "display-mode"
	gsKeyBrightness  = "brightness"
	gsKeySetter      = "brightness-setter"
	gsKeyMapOutput   = "map-output"
	gsKeyRateFilter  = "rate-filter"
	//gsKeyPrimary     = "primary"
	gsKeyCustomMode              = "current-custom-mode"
	gsKeyColorTemperatureMode    = "color-temperature-mode"
	gsKeyColorTemperatureManual  = "color-temperature-manual"
	gsKeyRotateScreenTimeDelay   = "rotate-screen-time-delay"
	customModeDelim              = "+"
	monitorsIdDelimiter          = ","
	defaultTemperatureMode       = ColorTemperatureModeNone
	defaultTemperatureManual     = 6500
	defaultRotateScreenTimeDelay = 500

	cmdTouchscreenDialogBin = "/usr/lib/deepin-daemon/dde-touchscreen-dialog"

	gsSchemaXSettings = "com.deepin.xsettings"
	gsKeyScaleFactor  = "scale-factor"
)

const (
	priorityEDP = iota
	priorityDP
	priorityHDMI
	priorityDVI
	priorityVGA
	priorityOther
)

var (
	_monitorTypePriority = map[string]int{
		"edp":  priorityEDP,
		"dp":   priorityDP,
		"hdmi": priorityHDMI,
		"dvi":  priorityDVI,
		"vga":  priorityVGA,
	}
)

var (
	startBuildInScreenRotationMutex sync.Mutex
	rotationScreenValue             = map[string]uint16{
		"normal": randr.RotationRotate0,
		"left":   randr.RotationRotate270, // 屏幕重力旋转左转90
		"right":  randr.RotationRotate90,  // 屏幕重力旋转右转90
	}
)

type touchscreenMapValue struct {
	OutputName string
	Auto       bool
}

//go:generate dbusutil-gen -output display_dbusutil.go -import github.com/godbus/dbus,github.com/linuxdeepin/go-x11-client,github.com/linuxdeepin/go-lib/strv -type Manager,Monitor manager.go monitor.go
//go:generate dbusutil-gen em -type Manager,Monitor

type Manager struct {
	service        *dbusutil.Service
	sysBus         *dbus.Conn
	sysSigLoop     *dbusutil.SignalLoop
	sessionSigLoop *dbusutil.SignalLoop
	// 系统级 dbus-daemon 服务
	dbusDaemon   ofdbus.DBus
	sensorProxy  dbus.BusObject
	inputDevices inputdevices.InputDevices
	// 系统级 display 服务
	sysDisplay sysdisplay.Display
	xConn      *x.Conn
	PropsMu    sync.RWMutex
	sysConfig  SysRootConfig
	userConfig UserConfig
	userCfgMu  sync.Mutex

	recommendScaleFactor     float64
	builtinMonitor           *Monitor
	builtinMonitorMu         sync.Mutex
	candidateBuiltinMonitors []*Monitor // 候补的

	monitorMap     map[uint32]*Monitor
	monitorMapMu   sync.Mutex
	mm             monitorManager
	debugOpts      debugOptions
	redshiftRunner *redshiftRunner

	sessionActive bool
	newSysCfg     *SysRootConfig
	cursorShowed  bool

	// gsettings com.deepin.dde.display
	settings                 *gio.Settings
	xSettingsGs              *gio.Settings
	monitorsId               monitorsId
	monitorsIdMu             sync.Mutex
	hasBuiltinMonitor        bool
	rotateScreenTimeDelay    int32
	setFillModeMu            sync.Mutex
	delayApplyTimer          *time.Timer
	delayApplyOptions        applyOptions
	prevCurrentNumMonitors   int
	prevNumMonitors          int
	prevNumMonitorsUpdatedAt time.Time
	delaySwitchMode          *delaySwitchMode
	applyMu                  sync.Mutex
	applySaveMu              sync.Mutex
	inApply                  bool
	futureConfig             monitorsFutureConfig

	// dbusutil-gen: equal=objPathsEqual
	Monitors []dbus.ObjectPath
	// dbusutil-gen: equal=nil
	CustomIdList []string
	HasChanged   bool
	DisplayMode  byte
	// dbusutil-gen: equal=nil
	Brightness map[string]float64

	// dbusutil-gen: equal=nil
	Touchscreens dxTouchscreens
	tm           touchscreenManager

	// dbusutil-gen: equal=nil
	TouchscreensV2 dxTouchscreens
	// dbusutil-gen: equal=nil
	TouchMap       map[string]string
	touchscreenMap map[string]touchscreenMapValue
	// touch.uuid -> touchScreenDialog cmd
	touchScreenDialogMap   map[string]*exec.Cmd
	touchScreenDialogMutex sync.RWMutex

	CurrentCustomId        string
	Primary                string
	PrimaryRect            x.Rectangle
	ScreenWidth            uint16
	ScreenHeight           uint16
	MaxBacklightBrightness uint32

	// method of adjust color temperature according to time and location
	ColorTemperatureMode int32
	// adjust color temperature by manual adjustment
	ColorTemperatureManual int32
	// TODO 删除下面 2 个色温相关字段
	// 存在gsetting中的色温模式
	gsColorTemperatureMode int32
	// 存在gsetting中的色温值
	gsColorTemperatureManual int32
	// 不支持调节色温的显卡型号
	unsupportGammaDrmList []string
	drmSupportGamma       bool
}

type monitorSizeInfo struct {
	width, height     uint16
	mmWidth, mmHeight uint32
}

var _ monitorManagerHooks = (*Manager)(nil)

func newManager(service *dbusutil.Service) *Manager {
	m := &Manager{
		service:        service,
		monitorMap:     make(map[uint32]*Monitor),
		Brightness:     make(map[string]float64),
		redshiftRunner: newRedshiftRunner(),
		unsupportGammaDrmList: []string{
			"Loongson",
		},
	}
	m.redshiftRunner.cb = func(value int) {
		m.setColorTempOneShot()
	}

	chassis, err := getComputeChassis()
	if err != nil {
		logger.Warning(err)
	}
	if chassis == "laptop" || chassis == "all-in-one" {
		m.hasBuiltinMonitor = true
	}

	m.settings = gio.NewSettings(gsSchemaDisplay)
	m.CurrentCustomId = m.settings.GetString(gsKeyCustomMode)
	m.rotateScreenTimeDelay = m.settings.GetInt(gsKeyRotateScreenTimeDelay)
	m.ColorTemperatureManual = defaultTemperatureManual
	m.ColorTemperatureMode = defaultTemperatureMode

	m.xSettingsGs = gio.NewSettings(gsSchemaXSettings)

	m.xConn = _xConn

	screen := m.xConn.GetDefaultScreen()
	if screen != nil {
		m.ScreenWidth = screen.WidthInPixels
		m.ScreenHeight = screen.HeightInPixels
	}
	sessionSigLoop := dbusutil.NewSignalLoop(m.service.Conn(), 10)
	m.sessionSigLoop = sessionSigLoop
	sessionSigLoop.Start()

	m.sysBus, err = dbus.SystemBus()
	if err != nil {
		logger.Warning(err)
	}

	if _useWayland {
		m.mm = newKMonitorManager(sessionSigLoop)
		m.tm = newWaylandTouchscreenManager(service.Conn(), m.sysBus)
	} else {
		m.mm = newXMonitorManager(m.xConn, _hasRandr1d2)
		m.tm = newXTouchscreenManager(m.sysBus)
	}

	m.mm.setHooks(m)

	m.setPropMaxBacklightBrightness(uint32(brightness.GetMaxBacklightBrightness()))

	sysSigLoop := dbusutil.NewSignalLoop(m.sysBus, 10)
	m.sysSigLoop = sysSigLoop
	sysSigLoop.Start()

	m.dbusDaemon = ofdbus.NewDBus(m.sysBus)
	m.dbusDaemon.InitSignalExt(sysSigLoop, true)

	m.inputDevices = inputdevices.NewInputDevices(m.sysBus)
	m.inputDevices.InitSignalExt(sysSigLoop, true)

	m.sysDisplay = sysdisplay.NewDisplay(m.sysBus)

	loginManager := login1.NewManager(m.sysBus)
	loginManager.InitSignalExt(sysSigLoop, true)
	/* 当系统从待机或者休眠状态唤醒时，需要重新获取当前屏幕的状态 */
	_, err = loginManager.ConnectPrepareForSleep(func(isSleep bool) {
		if !isSleep {
			logger.Info("system Wakeup, need reacquire screen status", isSleep)
			m.initScreenRotation()

			logger.Info("Cancel wm blackscreen effect")
			cmd := exec.Command("/bin/bash", "-c", "dbus-send --print-reply --dest=org.kde.KWin /BlackScreen org.kde.kwin.BlackScreen.setActive boolean:false")
			error := cmd.Run()
			if error != nil {
				logger.Warning("Cancel wm blackscreen failed", error)
			}
		}
	})

	if err != nil {
		logger.Warning("failed to connect signal PrepareForSleep:", err)
	}

	selfSessionPath, err := loginManager.GetSessionByPID(0, uint32(os.Getpid()))
	if err != nil {
		logger.Warningf("get session path failed: %v", err)
		// 允许在不能获取 session path 时提早结束
		return m
	}
	logger.Debug("self session path:", selfSessionPath)
	selfSession, err := login1.NewSession(m.sysBus, selfSessionPath)
	if err != nil {
		logger.Warning(err)
		return m
	}

	selfSession.InitSignalExt(sysSigLoop, true)
	err = selfSession.Active().ConnectChanged(func(hasValue, active bool) {
		if !hasValue {
			return
		}
		logger.Debug("session active changed", active)

		m.sessionActive = active
		if !active {
			return
		}
		if m.newSysCfg != nil {
			m.handleSysConfigUpdated(m.newSysCfg)
			m.newSysCfg = nil
		}

		m.handleTouchscreenChanged()
		m.showTouchscreenDialogs()

		// 监听用户的session Active属性改变信号，当切换到当前已经登录的用户时
		// 需要从内核重新获取当前屏幕的状态，将锁屏界面旋转到对应方向
		if m.builtinMonitor != nil {
			m.initScreenRotation()
		}
	})
	if err != nil {
		logger.Warningf("prop active ConnectChanged failed! %v", err)
	}

	m.sessionActive, err = selfSession.Active().Get(0)
	if err != nil {
		logger.Warning(err)
	}

	m.drmSupportGamma, _ = m.detectDrmSupportGamma()
	if m.drmSupportGamma {
		m.setColorTempModeReal(ColorTemperatureModeNone)
	}
	return m
}

// 初始化系统级 display 服务的信号处理
func (m *Manager) initSysDisplay() {
	m.sysDisplay.InitSignalExt(m.sysSigLoop, true)
	_, err := m.sysDisplay.ConnectConfigUpdated(func(updateAt string) {
		logger.Debug("sys display ConfigUpdated", updateAt)
		if updateAt == m.sysConfig.UpdateAt {
			return
		}

		newSysConfig, err := m.getSysConfig()
		if err != nil {
			// 获取出错，忽略这一次更新信号
			logger.Warning("getSysConfig err:", err)
			return
		}
		if logger.GetLogLevel() == log.LevelDebug {
			logger.Debug("get new sysConfig:", spew.Sdump(newSysConfig))
		}

		if !m.sessionActive {
			m.newSysCfg = newSysConfig
			return
		}

		m.handleSysConfigUpdated(newSysConfig)
	})
	if err != nil {
		logger.Warning(err)
	}
}

// 处理系统级别的配置更新
func (m *Manager) handleSysConfigUpdated(newSysConfig *SysRootConfig) {
	logger.Debug("handleSysConfigUpdated")
	setCfg := func() {
		m.sysConfig.copyFrom(newSysConfig)
	}

	currentCfg := &m.sysConfig.Config
	newCfg := &newSysConfig.Config
	cfgEq := reflect.DeepEqual(currentCfg, newCfg)
	if cfgEq {
		// 具体配置没有任何改变
		logger.Debug("cfg eq")
		setCfg()
		return
	}

	monitorMap := m.cloneMonitorMap()
	monitors := getConnectedMonitors(monitorMap)
	newCfg.updateUuid(monitors)

	fillModesEq := reflect.DeepEqual(currentCfg.FillModes, newCfg.FillModes)
	displayModeEq := currentCfg.DisplayMode == newCfg.DisplayMode
	scaleFactorsEq := reflect.DeepEqual(currentCfg.ScaleFactors, newCfg.ScaleFactors)
	single := len(monitors) == 1
	monitorsId := monitors.getMonitorsId()
	currentMonitorCfgs := currentCfg.getMonitorConfigs(monitorsId, currentCfg.DisplayMode, single)
	currentMonitorCfgs.sort()
	newMonitorCfgs := newCfg.getMonitorConfigs(monitorsId, currentCfg.DisplayMode, single)
	newMonitorCfgs.sort()
	monitorCfgsEq := reflect.DeepEqual(currentMonitorCfgs, newMonitorCfgs)
	logger.Debugf("fillModeEq: %v, displayModeEq: %v, scaleFactorsEq: %v, monitorCfgsEq: %v, monitorsId: %v, single: %v",
		fillModesEq, displayModeEq, scaleFactorsEq, monitorCfgsEq, monitorsId, single)
	if logger.GetLogLevel() == log.LevelDebug {
		logger.Debugf("currentMonitorCfgs: %s", spew.Sdump(currentMonitorCfgs))
		logger.Debugf("newMonitorCfgs: %s", spew.Sdump(newMonitorCfgs))
	}

	setCfg()

	if !scaleFactorsEq {
		// scale factors 改变了
		logger.Debug("scaleFactors changed")
		if ScaleFactorsHelper.changedCb != nil {
			go func() {
				err := ScaleFactorsHelper.changedCb(newCfg.ScaleFactors)
				if err != nil {
					logger.Warning("scale factors changed cb err:", err)
				}
			}()
		} else {
			logger.Warning("scale factors changed cb is nil")
		}
	}

	if !displayModeEq {
		// displayMode 改变了
		logger.Debug("displayMode changed")
		go func() {
			err := m.applyDisplayConfig(newCfg.DisplayMode, monitorsId, monitorMap, false, nil)
			if err != nil {
				logger.Warning(err)
				return
			}
			m.setPropDisplayMode(newCfg.DisplayMode)
		}()
		return
	}

	// 以下都是 displayMode 没变

	doApply := false
	if !monitorCfgsEq {
		if currentMonitorCfgs.onlyBrNotEq(newMonitorCfgs) {
			// 仅亮度改变
			logger.Debug("monitorCfgs not eq, but only brightness changed")
			go func() {
				for _, config := range newMonitorCfgs {
					if config.Enabled {
						err := m.setBrightness(config.Name, config.Brightness)
						if err != nil {
							logger.Warning(err)
						}
					}
				}
				m.syncPropBrightness()
			}()
		} else {
			// 不光是亮度改变，还有其他屏幕配置，比如位置pos，分辨率等改变。
			logger.Debug("monitor configs changed")
			doApply = true
			go func() {
				err := m.applySysMonitorConfigs(newCfg.DisplayMode, monitorsId, monitorMap, newMonitorCfgs, nil)
				if err != nil {
					logger.Warning(err)
					return
				}
			}()
		}
	}

	if !fillModesEq {
		// fillModes 改变了
		if !doApply {
			// applySysMonitorConfigs 会在内部设置 fillMode
			logger.Debug("fillModes changed, set fill mode for monitors")
			monitors := m.getConnectedMonitors()
			var primaryScreenFillMode = fillModeDefault
			for _, config := range newMonitorCfgs {
				if config.Primary {
					primaryScreenFillMode = newCfg.FillModes[monitors.GetByName(config.Name).generateFillModeKey()]
					break
				}
			}

			go func() {
				// 设置 fillModes
				for _, monitor := range monitors {
					var monitorFillMode = fillModeDefault
					if newCfg.DisplayMode == DisplayModeMirror {
						monitorFillMode = primaryScreenFillMode
					} else {
						monitorFillMode = newCfg.FillModes[monitor.generateFillModeKey()]
					}

					err := m.mm.setMonitorFillMode(monitor, monitorFillMode)
					if err != nil {
						logger.Warning("set monitor fill mode failed:", monitor, err)
					}
				}
			}()
		}
	}
}

// initBuiltinMonitor 初始化内置显示器。
func (m *Manager) initBuiltinMonitor() {
	if !m.hasBuiltinMonitor {
		return
	}
	// 从系统级配置中获取内置显示器名称
	builtinMonitorName := m.sysConfig.Config.Cache.BuiltinMonitor

	monitors := m.getConnectedMonitors()
	if builtinMonitorName != "" {
		for _, monitor := range monitors {
			if monitor.Name == builtinMonitorName {
				m.builtinMonitor = monitor
			}
		}
	}

	// 从配置文件获取的内置显示器还存在，信任配置文件，可以返回了
	if m.builtinMonitor != nil {
		return
	}
	builtinMonitorName = ""

	var rest []*Monitor
	for _, monitor := range monitors {
		name := strings.ToLower(monitor.Name)
		if strings.HasPrefix(name, "vga") {
			// 忽略 vga 开头的
		} else if strings.HasPrefix(name, "edp") {
			// 如果是 edp 开头，直接成为 builtinMonitor
			rest = []*Monitor{monitor}
			break
		} else {
			rest = append(rest, monitor)
		}
	}

	if len(rest) == 1 {
		m.builtinMonitor = rest[0]
		builtinMonitorName = m.builtinMonitor.Name
	} else if len(rest) > 1 {
		// 选择 id 最小的显示器作为内置显示器，这个结果不太准确，但却无可奈何。
		// 不保存 builtinMonitor 到配置文件中，由于 builtinMonitorName 为空，就会清空配置文件。
		m.builtinMonitor = getMinIdMonitor(rest)
		// 把剩余显示器列表 rest 设置到候选内置显示器列表。
		m.candidateBuiltinMonitors = rest
	}

	// 保存内置显示器配置文件
	err := m.saveBuiltinMonitorConfig(builtinMonitorName)
	if err != nil {
		logger.Warning("failed to save builtin monitor config:", err)
	}
}

// updateBuiltinMonitorOnDisconnected 在发现显示器断开连接时，更新内置显示器，因为断开的不可能是内置显示器。
// 参数 id 是断开的显示器的 id。
func (m *Manager) updateBuiltinMonitorOnDisconnected(id uint32) {
	m.builtinMonitorMu.Lock()
	defer m.builtinMonitorMu.Unlock()

	if len(m.candidateBuiltinMonitors) < 2 {
		return
	}
	m.candidateBuiltinMonitors = monitorsRemove(m.candidateBuiltinMonitors, id)
	if len(m.candidateBuiltinMonitors) == 1 {
		// 当只剩下一个候补时能自动成为真的 builtin monitor
		m.builtinMonitor = m.candidateBuiltinMonitors[0]
		m.candidateBuiltinMonitors = nil
		// 保存内置显示器配置文件
		err := m.saveBuiltinMonitorConfig(m.builtinMonitor.Name)
		if err != nil {
			logger.Warning("failed to save builtin monitor config:", err)
		}
	}
}

// monitorsRemove 删除 monitors 列表中显示器 id 为参数 id 的显示器，返回新列表
func monitorsRemove(monitors []*Monitor, id uint32) []*Monitor {
	var result []*Monitor
	for _, m := range monitors {
		if m.ID != id {
			result = append(result, m)
		}
	}
	return result
}

func (m *Manager) buildConfigForSingle(monitor *Monitor) SysMonitorConfigs {
	cfg := monitor.toBasicSysConfig()
	cfg.Enabled = true
	cfg.Primary = true
	mode := monitor.BestMode
	cfg.Width = mode.Width
	cfg.Height = mode.Height
	cfg.RefreshRate = mode.Rate
	// cfg.X = 0
	// cfg.Y = 0
	cfg.Brightness = 1
	cfg.Rotation = randr.RotationRotate0
	//cfg.Reflect = 0
	return SysMonitorConfigs{cfg}
}

func (m *Manager) applyDisplayConfig(mode byte, monitorsId monitorsId, monitorMap map[uint32]*Monitor, setColorTemp bool, options applyOptions) error {
	if monitorsId.v1 == "" {
		return errors.New("monitorsId is empty")
	}
	// X 环境下，如果 randr 版本低于 1.2 时，不做操作
	if !_useWayland && !_hasRandr1d2 {
		return nil
	}
	monitors := getConnectedMonitors(monitorMap)
	if len(monitors) == 0 {
		// 拔掉所有显示器
		logger.Debug("applyDisplayConfig not found any connected monitor，return")
		return nil
	}
	m.updateConfigUuid(monitors)

	if setColorTemp {
		m.applyColorTempConfig(mode)
	}

	defer func() {
		if _useWayland {
			m.updateScreenSize()
		}
	}()

	os.Setenv("D_DXCB_FORCE_OVERRIDE_HIDPI", "1")
	scale := strconv.FormatFloat(m.xSettingsGs.GetDouble(gsKeyScaleFactor), 'f', -1, 64)
	var value string
	for i := 0; i < len(monitors); i++ {
		value += scale + ";"
	}
	value = strings.TrimRight(value, ";")
	os.Setenv("QT_SCREEN_SCALE_FACTORS", value)

	var err error
	if len(monitors) == 1 {
		// 单屏情况
		screenCfg := m.getSysScreenConfig(monitorsId)

		needSaveCfg := false

		monitorConfigs := screenCfg.getSingleMonitorConfigs()
		if len(monitorConfigs) == 0 {
			// 没有单屏配置
			needSaveCfg = true
			monitorConfigs = m.buildConfigForSingle(monitors[0])
		}

		// 应用配置
		err = m.applySysMonitorConfigs(DisplayModeInvalid, monitorsId, monitorMap, monitorConfigs, options)
		if err != nil {
			logger.Warning("failed to apply configs:", err)
			return err
		}
		if needSaveCfg {
			screenCfg.setSingleMonitorConfigs(monitorConfigs)
			m.setSysScreenConfig(monitorsId, screenCfg)
			err = m.saveSysConfig("single")
			if err != nil {
				logger.Warning(err)
			}
		}
		return nil
	}
	// 多屏情况
	switch mode {
	case DisplayModeMirror:
		err = m.applyModeMirror(monitorsId, monitorMap, options)
	case DisplayModeExtend:
		err = m.applyModeExtend(monitorsId, monitorMap, options)
	case DisplayModeOnlyOne:
		err = m.applyModeOnlyOne(monitorsId, monitorMap, options)
	}

	if err != nil {
		logger.Warning(err)
		return err
	}
	return nil
}

// 在显示器断开或连接时，monitorsId 会改变，重新应用与之相符合的显示配置。
func (m *Manager) updateMonitorsId(options applyOptions) (changed bool) {
	m.monitorsIdMu.Lock()
	defer m.monitorsIdMu.Unlock()
	// NOTE: 加锁为了保护 monitorsId 和 delayApplyTimer

	oldMonitorsId := m.monitorsId
	monitorMap := m.cloneMonitorMap()
	newMonitorsId := getConnectedMonitors(monitorMap).getMonitorsId()
	if newMonitorsId != oldMonitorsId && newMonitorsId.v1 != "" {
		m.monitorsId = newMonitorsId
		logger.Debugf("monitors id changed, old monitors id: %v, new monitors id: %v", oldMonitorsId.v1, newMonitorsId.v1)
		m.markClean()

		const delayApplyDuration = 1 * time.Second
		if m.delayApplyTimer == nil {
			m.delayApplyTimer = time.AfterFunc(delayApplyDuration, m.delayApplyConfig)
		}
		m.setDelayApplyOptions(options)
		m.delayApplyTimer.Stop()
		// timer Reset 之前需要 Stop
		m.delayApplyTimer.Reset(delayApplyDuration)
	}
	return false
}

func (m *Manager) delayApplyConfig() {
	options := m.getDelayApplyOptions()
	// NOTE: applyConfig 应在非 X 事件处理的另外一个 goroutine 中进行。

	monitorMap := m.cloneMonitorMap()
	monitors := getConnectedMonitors(monitorMap)
	monitorsId := monitors.getMonitorsId()

	m.PropsMu.Lock()
	delay := m.delaySwitchMode
	m.PropsMu.Unlock()

	var paths []dbus.ObjectPath
	if delay != nil && len(monitors) > 1 && time.Since(delay.time) < 4*time.Second {
		logger.Debug("delay != nil and len(monitors) > 1")
		logger.Debug("since delay.time:", time.Since(delay.time))
		// 这个 time.Since(delay.time) 一般是 1.5s 左右。
		opts := getSwitchModeOptions(delay.mode, delay.name)
		logger.Debugf("delay call switchModeAux, delaySwitchMode: %+v", delay)
		err := m.switchModeAux(delay.mode, delay.oldMode, monitorsId, monitorMap, true, opts)
		if err != nil {
			logger.Warning("switch mode failed:", err)
		}

		paths = monitors.getPaths()

		m.PropsMu.Lock()
		m.delaySwitchMode = nil
		m.PropsMu.Unlock()

	} else {
		logger.Debugf("delay call applyConfig, monitorsId: %v, options: %v", monitorsId, options)

		m.applySaveMu.Lock()
		paths = m.applyConfig(true, options)
		m.applySaveMu.Unlock()
	}

	logger.Debug("update prop Monitors:", paths)
	m.PropsMu.Lock()
	m.setPropMonitors(paths)
	m.PropsMu.Unlock()
}

func (m *Manager) getDelayApplyOptions() applyOptions {
	m.PropsMu.Lock()
	options := m.delayApplyOptions
	m.PropsMu.Unlock()
	return options
}

func (m *Manager) setDelayApplyOptions(options applyOptions) {
	m.PropsMu.Lock()
	m.delayApplyOptions = options
	m.PropsMu.Unlock()
}

// applyConfig 应用显示配置，允许根据实际情况自动切换模式。
func (m *Manager) applyConfig(setColorTemp bool, options applyOptions) (paths []dbus.ObjectPath) {
	monitorMap := m.cloneMonitorMap()
	monitors := getConnectedMonitors(monitorMap)
	monitorsId := monitors.getMonitorsId()
	logger.Debugf("applyConfig monitorsId: %v, options: %v", monitorsId, options)

	m.PropsMu.RLock()
	displayMode := m.DisplayMode
	m.PropsMu.RUnlock()

	// 3个及以上屏幕，如果当前显示模式是 OnlyOne，需要自动切换到 Mirror 显示模式。
	if displayMode == DisplayModeOnlyOne && len(monitors) >= 3 {
		logger.Debug("switchMode mirror", monitorsId)
		err := m.switchModeAux(DisplayModeMirror, displayMode, monitorsId, monitorMap, setColorTemp, options)
		if err != nil {
			logger.Warning(err)
		}
	} else {
		err := m.applyDisplayConfig(displayMode, monitorsId, monitorMap, setColorTemp, options)
		if err != nil {
			logger.Warning(err)
		}
	}

	return monitors.getPaths()
}

func (m *Manager) migrateOldConfig() {
	if _greeterMode {
		// greeter 模式无法读取gsetting值，在没有显示系统级配置文件时，默认多屏模式为扩展
		m.sysConfig.mu.Lock()
		m.sysConfig.Config.DisplayMode = DisplayModeExtend
		m.DisplayMode = m.sysConfig.Config.DisplayMode
		m.sysConfig.mu.Unlock()
		return
	}
	logger.Debug("migrateOldConfig")

	// 当系统级配置文件不存在时，此时的display Mode取gsetting中的值，确保升级前后一致
	m.sysConfig.mu.Lock()
	m.sysConfig.Config.DisplayMode = uint8(m.settings.GetEnum(gsKeyDisplayMode))
	m.DisplayMode = m.sysConfig.Config.DisplayMode
	m.sysConfig.mu.Unlock()
	// NOTE: 在设置 m.DisplayMode, m.Brightness, m.gsColorTemperatureMode, m.gsColorTemperatureManual 之后
	// 再加载配置文件并迁移，主要原因是 loadOldConfig 中的 ConfigV3D3.toConfig 和 ConfigV4.toConfig 需要。
	m.gsColorTemperatureMode = m.settings.GetInt(gsKeyColorTemperatureMode)
	m.gsColorTemperatureManual = m.settings.GetInt(gsKeyColorTemperatureManual)
	m.initBrightness()
	configV6, err := loadOldConfig(m)
	if err != nil {
		// 旧配置加载失败
		if !os.IsNotExist(err) {
			logger.Warning(err)
		}
	} else {
		// 旧配置加载成功
		if logger.GetLogLevel() == log.LevelDebug {
			logger.Debug("migrateOldConfig configV6:", spew.Sdump(configV6))
		}
		sysCfg := configV6.toSysConfigV1()
		sysCfg.DisplayMode = m.DisplayMode
		m.sysConfig.Config = sysCfg
		m.userConfig = configV6.toUserConfigV1()
		m.userConfig.fix()
		if err := m.saveUserConfig(); err != nil {
			logger.Warning(err)
		}
	}

	cfgDir := getCfgDir()
	// 内置显示器配置文件 ~/.config/deepin/startdde/builtin-monitor
	builtinMonitorConfigFile := filepath.Join(cfgDir, "builtin-monitor")
	builtinMonitor, err := loadBuiltinMonitorConfig(builtinMonitorConfigFile)
	if err != nil {
		if !os.IsNotExist(err) {
			logger.Warning(err)
		}
	} else {
		m.sysConfig.Config.Cache.BuiltinMonitor = builtinMonitor
	}

	// NOTE: 这里的 cache 文件路径就是错的 ~/.cache/deepin/startdded/connectifno.cache
	connectCacheFile := filepath.Join(basedir.GetUserCacheDir(),
		"deepin/startdded/connectifno.cache")
	connectInfo, err := readConnectInfoCache(connectCacheFile)
	if err != nil {
		if !os.IsNotExist(err) {
			logger.Warning(err)
		}
	} else {
		connectTime := make(map[string]time.Time)
		for name, connected := range connectInfo.Connects {
			if connected {
				if t, ok := connectInfo.LastConnectedTimes[name]; ok {
					connectTime[name] = t
				}
			}
		}
		m.sysConfig.Config.Cache.ConnectTime = connectTime
	}

	m.sysConfig.fix()
	if err := m.saveSysConfigNoLock("migrate old config"); err != nil {
		logger.Warning(err)
	}
}

func (m *Manager) init() {
	brightness.InitBacklightHelper()
	brightness.SetUseWayland(_useWayland)
	m.initDebugOptions()
	m.loadSysConfig()
	if m.sysConfig.Version == "" {
		// 系统配置为空，需要迁移旧配置
		m.migrateOldConfig()
	}

	if _scaleFactors != nil {
		err := m.setScaleFactors(_scaleFactors)
		if err != nil {
			logger.Warning(err)
		}
		_scaleFactors = nil
	}

	if _hasRandr1d2 || _useWayland {
		monitors := m.mm.getMonitors()
		logger.Debug("len monitors", len(monitors))
		err := m.recordMonitorsConnected(monitors)
		if err != nil {
			logger.Warning(err)
		}

		for _, monitor := range monitors {
			err := m.addMonitor(monitor)
			if err != nil {
				logger.Warning(err)
			}
		}

		m.initBuiltinMonitor()
		m.monitorsId = m.getMonitorsId()
		m.updatePropMonitors()

		pmi := m.mm.getPrimaryMonitor()
		if pmi != nil {
			m.setPropPrimary(pmi.Name)
			m.setPropPrimaryRect(pmi.getRect())
		}

	} else {
		// randr 版本低于 1.2
		screen := m.xConn.GetDefaultScreen()
		screenInfo, err := randr.GetScreenInfo(m.xConn, screen.Root).Reply(m.xConn)
		if err == nil {
			monitor, err := m.addMonitorFallback(screenInfo)
			if err == nil {
				m.updatePropMonitors()
				m.setPropPrimary("Default")
				m.setPropPrimaryRect(x.Rectangle{
					X:      monitor.X,
					Y:      monitor.Y,
					Width:  monitor.Width,
					Height: monitor.Height,
				})
			} else {
				logger.Warning(err)
			}
		} else {
			logger.Warning(err)
		}
	}

	m.DisplayMode = m.sysConfig.Config.DisplayMode

	err := m.loadUserConfig()
	if err != nil {
		logger.Warning("loadUserConfig err:", err)
	}

	// NOTE: m.listenXEvents 应该在 m.applyDisplayConfig 之前，否则会造成它里面的 m.apply 函数的等待超时。
	m.listenXEvents()
	// 此时不需要设置色温，在 StartPart2 中做。为性能考虑。
	m.applyConfig(false, nil)
	if m.builtinMonitor != nil {
		m.listenSettingsChanged() // 监听旋转屏幕延时值
		m.initScreenRotation()    // 获取初始屏幕的状态（屏幕方向）
		m.listenRotateSignal()    // 监听屏幕旋转信号
	} else {
		// 没有内建屏,不监听内核信号
		logger.Info("built-in screen does not exist")
	}
}

// calcRecommendedScaleFactor 计算推荐的缩放比
func calcRecommendedScaleFactor(widthPx, heightPx, widthMm, heightMm float64) float64 {
	if widthMm == 0 || heightMm == 0 {
		return 1
	}

	lenPx := math.Hypot(widthPx, heightPx)
	lenMm := math.Hypot(widthMm, heightMm)

	lenPxStd := math.Hypot(1920, 1080)
	lenMmStd := math.Hypot(477, 268)

	const a = 0.00158
	fix := (lenMm - lenMmStd) * (lenPx / lenPxStd) * a
	scaleFactor := (lenPx/lenMm)/(lenPxStd/lenMmStd) + fix

	return toListedScaleFactor(scaleFactor)
}

func toListedScaleFactor(s float64) float64 {
	const (
		min  = 1.0
		max  = 3.0
		step = 0.25
	)
	if s <= min {
		return min
	} else if s >= max {
		return max
	}

	for i := min; i <= max; i += step {
		if i > s {
			ii := i - step
			d1 := s - ii
			d2 := i - s

			if d1 >= d2 {
				return i
			} else {
				return ii
			}
		}
	}
	return max
}

// 过滤掉部分模式，尽量不过滤掉 saveMode。
func (m *Manager) filterModeInfos(modeInfos []ModeInfo, saveMode ModeInfo) []ModeInfo {
	result := filterModeInfosByRefreshRate(filterModeInfos(modeInfos, saveMode), m.getRateFilter())
	return result
}

func getScreenInfoSize(screenInfo *randr.GetScreenInfoReply) (size randr.ScreenSize, err error) {
	sizeId := screenInfo.SizeID
	if int(sizeId) < len(screenInfo.Sizes) {
		size = screenInfo.Sizes[sizeId]
	} else {
		err = fmt.Errorf("size id out of range: %d %d", sizeId, len(screenInfo.Sizes))
	}
	return
}

func (m *Manager) addMonitorFallback(screenInfo *randr.GetScreenInfoReply) (*Monitor, error) {
	output := randr.Output(1)

	size, err := getScreenInfoSize(screenInfo)
	if err != nil {
		return nil, err
	}

	monitor := &Monitor{
		service:       m.service,
		m:             m,
		ID:            uint32(output),
		Name:          "Default",
		Connected:     true,
		realConnected: true,
		MmWidth:       uint32(size.MWidth),
		MmHeight:      uint32(size.MHeight),
		Enabled:       true,
		Width:         size.Width,
		Height:        size.Height,
	}

	err = m.service.Export(monitor.getPath(), monitor)
	if err != nil {
		return nil, err
	}
	m.monitorMapMu.Lock()
	m.monitorMap[uint32(output)] = monitor
	m.monitorMapMu.Unlock()
	return monitor, nil
}

func (m *Manager) updateMonitorFallback(screenInfo *randr.GetScreenInfoReply) *Monitor {
	output := randr.Output(1)
	m.monitorMapMu.Lock()
	monitor, ok := m.monitorMap[uint32(output)]
	m.monitorMapMu.Unlock()
	if !ok {
		return nil
	}

	size, err := getScreenInfoSize(screenInfo)
	if err != nil {
		logger.Warning(err)
		return nil
	}

	monitor.setPropWidth(size.Width)
	monitor.setPropHeight(size.Height)
	monitor.setPropMmWidth(uint32(size.MWidth))
	monitor.setPropMmHeight(uint32(size.MHeight))
	return monitor
}

func (m *Manager) recordMonitorsConnected(monitors []*MonitorInfo) (err error) {
	t := time.Now()
	needSave := false
	for _, monitor := range monitors {
		ns := m.recordMonitorConnectedAux(monitor.Name, monitor.Connected, t)
		needSave = needSave || ns
	}
	if needSave {
		err = m.saveSysConfig("monitors connected changed")
	}
	return err
}

func (m *Manager) recordMonitorConnected(name string, connected bool, t time.Time) (err error) {
	logger.Debug("recordMonitorConnected", name, connected, t)
	needSave := m.recordMonitorConnectedAux(name, connected, t)
	if needSave {
		err = m.saveSysConfig("monitor connected changed")
	}
	return err
}

func (m *Manager) recordMonitorConnectedAux(name string, connected bool, t time.Time) (needSave bool) {
	m.sysConfig.mu.Lock()
	connectTime := m.sysConfig.Config.Cache.ConnectTime
	if connected {
		// 连接
		if _, ok := connectTime[name]; !ok {
			if connectTime == nil {
				connectTime = make(map[string]time.Time)
				m.sysConfig.Config.Cache.ConnectTime = connectTime
			}
			connectTime[name] = t
			needSave = true
		}
	} else {
		// 断开
		if _, ok := connectTime[name]; ok {
			delete(connectTime, name)
			needSave = true
		}
	}
	m.sysConfig.mu.Unlock()
	return needSave
}

// addMonitor 在 Manager.monitorMap 增加显示器，在 dbus 上导出显示器对象
func (m *Manager) addMonitor(monitorInfo *MonitorInfo) error {
	m.monitorMapMu.Lock()
	_, ok := m.monitorMap[monitorInfo.ID]
	m.monitorMapMu.Unlock()
	if ok {
		return nil
	}

	logger.Debug("addMonitor", monitorInfo.Name)

	monitor := &Monitor{
		service:            m.service,
		m:                  m,
		ID:                 monitorInfo.ID,
		Name:               monitorInfo.Name,
		Connected:          monitorInfo.VirtualConnected,
		realConnected:      monitorInfo.Connected,
		MmWidth:            monitorInfo.MmWidth,
		MmHeight:           monitorInfo.MmHeight,
		Enabled:            monitorInfo.Enabled,
		uuid:               monitorInfo.UUID,
		uuidV0:             monitorInfo.UuidV0,
		Manufacturer:       monitorInfo.Manufacturer,
		Model:              monitorInfo.Model,
		AvailableFillModes: monitorInfo.AvailableFillModes,
	}

	monitor.Modes = m.filterModeInfos(monitorInfo.Modes, monitorInfo.PreferredMode)
	monitor.BestMode = getBestMode(monitor.Modes, monitorInfo.PreferredMode)
	if !monitor.BestMode.isZero() {
		monitor.PreferredModes = []ModeInfo{monitor.BestMode}
	}
	monitor.X = monitorInfo.X
	monitor.Y = monitorInfo.Y
	monitor.Width = monitorInfo.Width
	monitor.Height = monitorInfo.Height

	monitor.Reflects = getReflects(monitorInfo.Rotations)
	monitor.Rotations = getRotations(monitorInfo.Rotations)
	monitor.Rotation, monitor.Reflect = parseCrtcRotation(monitorInfo.Rotation)
	monitor.CurrentMode = monitorInfo.CurrentMode
	monitor.RefreshRate = monitorInfo.CurrentMode.Rate

	monitor.oldRotation = monitor.Rotation

	m.handleMonitorConnectedChanged(monitor, monitorInfo.Connected)

	err := m.service.Export(monitor.getPath(), monitor)
	if err != nil {
		return err
	}
	m.monitorMapMu.Lock()
	m.monitorMap[monitorInfo.ID] = monitor
	m.monitorMapMu.Unlock()

	monitorObj := m.service.GetServerObject(monitor)
	err = monitorObj.SetWriteCallback(monitor, "CurrentFillMode",
		monitor.setCurrentFillMode)
	if err != nil {
		logger.Warning("call SetWriteCallback err:", err)
		return err
	}

	return nil
}

// updateMonitor 根据 outputInfo 中的信息更新 dbus 上的 Monitor 对象的属性
func (m *Manager) updateMonitor(monitorInfo *MonitorInfo) {
	m.monitorMapMu.Lock()
	monitor, ok := m.monitorMap[monitorInfo.ID]
	m.monitorMapMu.Unlock()
	if !ok {
		err := m.addMonitor(monitorInfo)
		if err != nil {
			logger.Warning(err)
			return
		}

		return
	}
	logger.Debugf("updateMonitor %v", monitorInfo.Name)
	monitorInfo.dumpForDebug()

	m.handleMonitorConnectedChanged(monitor, monitorInfo.Connected)
	monitor.PropsMu.Lock()

	if monitor.uuid != monitorInfo.UUID {
		logger.Debugf("%v uuid changed, old:%q, new %q", monitor, monitor.uuid, monitorInfo.UUID)
	}
	monitor.uuid = monitorInfo.UUID
	monitor.uuidV0 = monitorInfo.UuidV0
	monitor.realConnected = monitorInfo.Connected
	monitor.setPropAvailableFillModes(monitorInfo.AvailableFillModes)
	monitor.setPropManufacturer(monitorInfo.Manufacturer)
	monitor.setPropModel(monitorInfo.Model)
	monitor.setPropModes(m.filterModeInfos(monitorInfo.Modes, monitorInfo.PreferredMode))
	bestMode := getBestMode(monitor.Modes, monitorInfo.PreferredMode)
	monitor.setPropBestMode(bestMode)
	var preferredModes []ModeInfo
	if !bestMode.isZero() {
		preferredModes = []ModeInfo{bestMode}
	}
	monitor.setPropPreferredModes(preferredModes)
	monitor.setPropMmWidth(monitorInfo.MmWidth)
	monitor.setPropMmHeight(monitorInfo.MmHeight)
	monitor.setPropX(monitorInfo.X)
	monitor.setPropY(monitorInfo.Y)
	monitor.setPropWidth(monitorInfo.Width)
	monitor.setPropHeight(monitorInfo.Height)
	// NOTE: 前端 dcc 要求在设置了 Width 和 Height 之后，再设置 Connected 和 Enabled。
	monitor.setPropConnected(monitorInfo.VirtualConnected)
	monitor.setPropEnabled(monitorInfo.Enabled)

	monitor.setPropReflects(getReflects(monitorInfo.Rotations))
	monitor.setPropRotations(getRotations(monitorInfo.Rotations))
	rotation, reflectProp := parseCrtcRotation(monitorInfo.Rotation)
	monitor.setPropRotation(rotation)
	monitor.setPropReflect(reflectProp)

	monitor.setPropCurrentMode(monitorInfo.CurrentMode)
	monitor.setPropRefreshRate(monitorInfo.CurrentMode.Rate)
	monitor.PropsMu.Unlock()

	m.updateScreenSize()
}

func (m *Manager) handleMonitorConnectedChanged(monitor *Monitor, connected bool) {
	err := m.recordMonitorConnected(monitor.Name, connected, time.Now())
	if err != nil {
		logger.Warning(err)
	}
	if connected {
		// 连接
	} else {
		// 断开
		m.updateBuiltinMonitorOnDisconnected(monitor.ID)
	}
}

func (m *Manager) buildConfigForModeMirror(monitors Monitors) (monitorCfgs SysMonitorConfigs, err error) {
	logger.Debug("switch mode mirror")
	commonSizes := getMonitorsCommonSizes(monitors)
	if len(commonSizes) == 0 {
		err = errors.New("not found common size")
		return
	}
	maxSize := getMaxAreaSize(commonSizes)
	primaryMonitor := m.getDefaultPrimaryMonitor(monitors)
	for _, monitor := range monitors {
		cfg := monitor.toBasicSysConfig()
		cfg.Enabled = true
		if monitor.ID == primaryMonitor.ID {
			cfg.Primary = true
		}
		mode := getFirstModeBySize(monitor.Modes, maxSize.width, maxSize.height)
		cfg.Width = mode.Width
		cfg.Height = mode.Height
		cfg.RefreshRate = mode.Rate
		cfg.X = 0
		cfg.Y = 0
		cfg.Rotation = randr.RotationRotate0
		cfg.Reflect = 0
		cfg.Brightness = 1
		monitorCfgs = append(monitorCfgs, cfg)
	}
	return
}

func (m *Manager) applyModeMirror(monitorsId monitorsId, monitorMap map[uint32]*Monitor, options applyOptions) (err error) {
	logger.Debug("apply mode mirror")
	monitors := getConnectedMonitors(monitorMap)
	screenCfg := m.getSysScreenConfig(monitorsId)

	needSaveCfg := false

	configs := screenCfg.getMonitorConfigs(DisplayModeMirror, "")

	if len(configs) == 0 {
		needSaveCfg = true
		configs, err = m.buildConfigForModeMirror(monitors)
		if err != nil {
			return
		}
	}

	err = m.applySysMonitorConfigs(DisplayModeMirror, monitorsId, monitorMap, configs, options)
	if err != nil {
		return
	}

	if needSaveCfg {
		screenCfg.setMonitorConfigs(DisplayModeMirror, "", configs)
		m.setSysScreenConfig(monitorsId, screenCfg)
		return m.saveSysConfig("mode mirror")
	}

	return
}

func (m *Manager) getSuitableSysMonitorConfigs(displayMode byte, monitorsId monitorsId, monitors Monitors) SysMonitorConfigs {
	screenCfg := m.getSysScreenConfig(monitorsId)
	if len(monitors) == 0 {
		return nil
	} else if len(monitors) == 1 {
		return screenCfg.getSingleMonitorConfigs()
	}
	uuid := getOnlyOneMonitorUuid(displayMode, monitors)
	return screenCfg.getMonitorConfigs(displayMode, uuid)
}

func (m *Manager) getSuitableUserMonitorModeConfig(displayMode byte) *UserMonitorModeConfig {
	monitors := m.getConnectedMonitors()
	screenCfg := m.getUserScreenConfig(monitors.getMonitorsId())
	if len(monitors) == 0 {
		return nil
	} else if len(monitors) == 1 {
		return screenCfg[KeySingle]
	}
	uuid := getOnlyOneMonitorUuid(displayMode, monitors)
	return screenCfg.getMonitorModeConfig(displayMode, uuid)
}

func (m *Manager) modifySuitableSysMonitorConfigs(fn func(configs SysMonitorConfigs) SysMonitorConfigs) {
	monitors := m.getConnectedMonitors()
	monitorsId := monitors.getMonitorsId()
	screenCfg := m.getSysScreenConfig(monitorsId)
	if len(monitors) == 0 {
		return
	} else if len(monitors) == 1 {
		configs := screenCfg.getSingleMonitorConfigs()
		configs = fn(configs)
		screenCfg.setSingleMonitorConfigs(configs)
	} else {
		displayMode := m.DisplayMode
		uuid := getOnlyOneMonitorUuid(displayMode, monitors)
		configs := screenCfg.getMonitorConfigs(displayMode, uuid)
		configs = fn(configs)
		screenCfg.setMonitorConfigs(displayMode, uuid, configs)
	}
	m.setSysScreenConfig(monitorsId, screenCfg)
}

// 获取 OnlyOne 显示模式下启用显示器的 UUID，其他显示模式下返回空。
func getOnlyOneMonitorUuid(displayMode byte, monitors Monitors) (uuid string) {
	if displayMode == DisplayModeOnlyOne {
		for _, monitor := range monitors {
			if monitor.Enabled {
				return monitor.uuid
			}
		}
	}
	return ""
}

func (m *Manager) modifySuitableUserMonitorModeConfig(fn func(cfg *UserMonitorModeConfig)) {
	monitors := m.getConnectedMonitors()
	monitorsId := monitors.getMonitorsId()
	screenCfg := m.getUserScreenConfig(monitorsId)

	if len(monitors) == 0 {
		return
	} else if len(monitors) == 1 {
		cfg := screenCfg[KeySingle]
		if cfg == nil {
			cfg = getDefaultUserMonitorModeConfig()
		}
		fn(cfg)
		screenCfg[KeySingle] = cfg
		m.setUserScreenConfig(monitorsId, screenCfg)
		return
	}
	displayMode := m.DisplayMode
	uuid := getOnlyOneMonitorUuid(displayMode, monitors)
	cfg := screenCfg.getMonitorModeConfig(displayMode, uuid)
	if cfg == nil {
		cfg = getDefaultUserMonitorModeConfig()
	}
	fn(cfg)
	screenCfg.setMonitorModeConfig(displayMode, uuid, cfg)
	m.setUserScreenConfig(monitorsId, screenCfg)
}

type screenSize struct {
	width    uint16
	height   uint16
	mmWidth  uint32
	mmHeight uint32
}

func (m *Manager) apply(monitorsId monitorsId, monitorMap map[uint32]*Monitor, options applyOptions, primaryMonitorID uint32, displayMode byte) error {
	// 当前的屏幕大小
	m.PropsMu.RLock()
	prevScreenSize := screenSize{width: m.ScreenWidth, height: m.ScreenHeight}
	m.PropsMu.RUnlock()
	m.setInApply(true)

	// NOTE: 应该限制只有 Manager.apply 才能调用 mm.apply
	m.applyMu.Lock()
	err := m.mm.apply(monitorsId, monitorMap, prevScreenSize, options, m.sysConfig.Config.FillModes, primaryMonitorID, displayMode)
	m.applyMu.Unlock()

	m.setInApply(false)

	logger.Info("redo map touch screen")
	m.handleTouchscreenChanged()

	return err
}

func (m *Manager) getInApply() bool {
	m.PropsMu.Lock()
	defer m.PropsMu.Unlock()
	return m.inApply
}

func (m *Manager) setInApply(value bool) {
	m.PropsMu.Lock()
	m.inApply = value
	m.PropsMu.Unlock()
}

func (m *Manager) handlePrimaryRectChanged(pmi *MonitorInfo) {
	logger.Debug("handlePrimaryRectChanged", pmi)
	m.PropsMu.Lock()
	defer m.PropsMu.Unlock()

	m.setPropPrimary(pmi.Name)
	m.setPropPrimaryRect(pmi.getRect())
}

func (m *Manager) setPrimary(name string) error {
	switch m.DisplayMode {
	case DisplayModeMirror:
		return errors.New("not allow set primary in mirror mode")

	case DisplayModeOnlyOne:
		options := applyOptions{
			optionOnlyOne: name,
		}
		monitorMap := m.cloneMonitorMap()
		monitorsId := getConnectedMonitors(monitorMap).getMonitorsId()
		return m.applyModeOnlyOne(monitorsId, monitorMap, options)

	case DisplayModeExtend:
		monitorMap := m.cloneMonitorMap()
		monitors := getConnectedMonitors(monitorMap)
		monitorsId := monitors.getMonitorsId()
		screenCfg := m.getSysScreenConfig(monitorsId)
		configs := screenCfg.getMonitorConfigs(DisplayModeExtend, "")

		var primaryMonitor *Monitor
		for _, monitor := range monitorMap {
			if monitor.Name != name {
				continue
			}

			if !monitor.realConnected {
				return errors.New("monitor is not connected")
			}

			primaryMonitor = monitor
			break
		}

		if primaryMonitor == nil {
			return errors.New("not found primary monitor")
		}

		if len(configs) == 0 {
			configs = toSysMonitorConfigs(monitors, primaryMonitor.Name)
		} else {
			// modify configs
			// TODO 这里为什么需要更新 Name？
			updateSysMonitorConfigsName(configs, m.monitorMap)
			configs.setPrimary(primaryMonitor.uuid)
		}

		err := m.mm.setMonitorPrimary(primaryMonitor.ID)
		if err != nil {
			return err
		}

		screenCfg.setMonitorConfigs(DisplayModeExtend, "", configs)
		m.setSysScreenConfig(monitorsId, screenCfg)
		err = m.saveSysConfig("primary changed")
		if err != nil {
			return err
		}

	default:
		return fmt.Errorf("invalid display mode %v", m.DisplayMode)
	}
	return nil
}

func (m *Manager) buildConfigForModeExtend(monitors Monitors) (monitorCfgs SysMonitorConfigs, err error) {
	// 先获取主屏
	var primaryMonitor *Monitor
	primaryMonitor = m.getDefaultPrimaryMonitor(monitors)

	sortMonitorsByPrimaryAndId(monitors, primaryMonitor)
	var xOffset int

	for _, monitor := range monitors {
		cfg := monitor.toBasicSysConfig()
		cfg.Enabled = true
		if monitor.ID == primaryMonitor.ID {
			cfg.Primary = true
		}
		mode := monitor.BestMode
		// 不用考虑旋转，默认不旋转
		cfg.Width = mode.Width
		cfg.Height = mode.Height
		cfg.RefreshRate = mode.Rate

		if xOffset > math.MaxInt16 {
			xOffset = math.MaxInt16
		}
		cfg.X = int16(xOffset)
		//cfg.Y = 0
		cfg.Rotation = randr.RotationRotate0
		//cfg.Reflect = 0
		cfg.Brightness = 1
		xOffset += int(cfg.Width)
		monitorCfgs = append(monitorCfgs, cfg)
	}
	return
}

func (m *Manager) applyModeExtend(monitorsId monitorsId, monitorMap map[uint32]*Monitor, options applyOptions) (err error) {
	logger.Debug("apply mode extend")
	monitors := getConnectedMonitors(monitorMap)
	screenCfg := m.getSysScreenConfig(monitorsId)

	needSaveCfg := false

	configs := screenCfg.getMonitorConfigs(DisplayModeExtend, "")

	if len(configs) == 0 {
		needSaveCfg = true
		configs, err = m.buildConfigForModeExtend(monitors)
		if err != nil {
			return
		}
	}

	err = m.applySysMonitorConfigs(DisplayModeExtend, monitorsId, monitorMap, configs, options)
	if err != nil {
		return
	}

	if needSaveCfg {
		screenCfg.setMonitorConfigs(DisplayModeExtend, "", configs)
		m.setSysScreenConfig(monitorsId, screenCfg)
		return m.saveSysConfig("mode extend")
	}
	return
}

func (m *Manager) buildConfigForModeOnlyOne(monitors Monitors, uuid string) (monitorCfgs SysMonitorConfigs, err error) {
	for _, monitor := range monitors {
		mode := monitor.BestMode
		cfg := monitor.toBasicSysConfig()
		if monitor.uuid == uuid {
			cfg.Enabled = true
			cfg.Primary = true
			cfg.Width = mode.Width
			cfg.Height = mode.Height
			cfg.RefreshRate = mode.Rate
			//cfg.X = 0
			//cfg.Y = 0
			cfg.Rotation = randr.RotationRotate0
			//cfg.Reflect = 0
			cfg.Brightness = 1
			monitorCfgs = append(monitorCfgs, cfg)
			return
		}
	}
	return
}

func (m *Manager) applyModeOnlyOne(monitorsId monitorsId, monitorMap map[uint32]*Monitor, options applyOptions) (err error) {
	name, _ := options[optionOnlyOne].(string)
	logger.Debug("apply mode only one", name)

	monitors := getConnectedMonitors(monitorMap)
	screenCfg := m.getSysScreenConfig(monitorsId)

	needSaveCfg := false

	uuid := ""
	if name == "" {
		// 未指定名称
		monitor := monitors.GetByUuid(screenCfg.OnlyOneUuid)
		if monitor != nil {
			uuid = monitor.uuid
		} // else 用默认主屏作为替补

	} else {
		// 指定了名称
		monitor := monitors.GetByName(name)
		if monitor != nil {
			uuid = monitor.uuid
			needSaveCfg = true
		} else {
			// 名称指定错误
			return InvalidOutputNameError{Name: name}
		}
	}

	if uuid == "" {
		primaryMonitor := m.getDefaultPrimaryMonitor(monitors)
		if primaryMonitor == nil {
			return errors.New("not found primary monitor")
		}
		uuid = primaryMonitor.uuid
		needSaveCfg = true
	}
	// 必须要有 uuid
	if uuid == "" {
		return errors.New("uuid is empty")
	}

	configs := screenCfg.getMonitorConfigs(DisplayModeOnlyOne, uuid)
	if len(configs) == 0 {
		needSaveCfg = true
		logger.Debug("buildConfigForModeOnlyOne", uuid)
		configs, err = m.buildConfigForModeOnlyOne(monitors, uuid)
		if err != nil {
			return
		}
	}

	err = m.applySysMonitorConfigs(DisplayModeOnlyOne, monitorsId, monitorMap, configs, options)
	if err != nil {
		return
	}

	if needSaveCfg {
		screenCfg.setMonitorConfigs(DisplayModeOnlyOne, uuid, configs)
		screenCfg.OnlyOneUuid = uuid
		m.setSysScreenConfig(monitorsId, screenCfg)
		return m.saveSysConfig("mode only one")
	}

	return
}

func (m *Manager) switchModeAux(mode, oldMode byte, monitorsId monitorsId, monitorMap map[uint32]*Monitor,
	setColorTemp bool, options applyOptions) (err error) {

	err = m.applyDisplayConfig(mode, monitorsId, monitorMap, setColorTemp, options)
	if err != nil {
		logger.Warning(err)
		return err
	}
	if oldMode != mode {
		// 保存设置
		m.sysConfig.mu.Lock()
		m.sysConfig.Config.DisplayMode = mode
		err = m.saveSysConfigNoLock("switch mode")
		m.sysConfig.mu.Unlock()

		if err != nil {
			logger.Warning(err)
			return err
		}
	}

	return nil
}

type delaySwitchMode struct {
	mode, oldMode byte
	name          string
	time          time.Time
}

func (m *Manager) switchMode(mode byte, name string) (err error) {
	oldMode := m.DisplayMode
	monitorMap := m.cloneMonitorMap()
	monitors := getConnectedMonitors(monitorMap)

	setDelaySwitch := func() {
		m.PropsMu.Lock()
		defer m.PropsMu.Unlock()

		if m.prevNumMonitors >= 2 && time.Since(m.prevNumMonitorsUpdatedAt) < 1*time.Second {
			// 距离上次显示器数量改变发生时间小于 1s，表示突发显示器断开事件。
			m.delaySwitchMode = &delaySwitchMode{
				mode:    mode,
				oldMode: oldMode,
				name:    name,
				time:    time.Now(),
			}
			logger.Debugf("switchMode set delaySwitchMode %+v, time: %v", m.delaySwitchMode, m.delaySwitchMode.time)
		}
	}

	if len(monitors) == 1 {
		setDelaySwitch()
		return nil
	}

	monitorsId := monitors.getMonitorsId()
	options := getSwitchModeOptions(mode, name)
	err = m.switchModeAux(mode, oldMode, monitorsId, monitorMap, true, options)
	if err != nil {
		applyErr, ok := err.(*applyFailed)
		if ok && applyErr.reason == reasonNumChanged {
			if len(applyErr.monitors) == 1 {
				setDelaySwitch()
				return nil
			}
		}
	}

	return err
}

func getSwitchModeOptions(mode byte, name string) applyOptions {
	options := applyOptions{
		// 替代之前的 modeChanged
		optionDisableCrtc: true,
	}
	if mode == DisplayModeOnlyOne && name != "" {
		options[optionOnlyOne] = name
	}
	return options
}

func (m *Manager) setDisplayMode(mode byte) {
	m.setPropDisplayMode(mode)
	m.sysConfig.Config.DisplayMode = mode
}

func (m *Manager) save() (err error) {
	if m.getInApply() {
		logger.Debug("no save, in apply")
		return nil
	}

	m.PropsMu.RLock()
	if !m.HasChanged {
		m.PropsMu.RUnlock()
		logger.Debug("no save, no changed")
		return nil
	}
	m.PropsMu.RUnlock()

	logger.Debug("save")
	monitorMap := m.cloneMonitorMap()
	monitors := getConnectedMonitors(monitorMap)
	if len(monitors) == 0 {
		err = errors.New("no monitor connected")
		return
	}
	monitorsId := monitors.getMonitorsId()

	screenCfg := m.getSysScreenConfig(monitorsId)

	configs := m.futureConfig.getConfigs(monitorsId)
	if len(configs) == 0 {
		logger.Debug("no save, no config")
		return
	}
	if len(monitors) == 1 {
		screenCfg.setSingleMonitorConfigs(configs)
	} else {
		uuid := getOnlyOneMonitorUuid(m.DisplayMode, monitors)
		screenCfg.setMonitorConfigs(m.DisplayMode, uuid, configs)
	}
	m.setSysScreenConfig(monitorsId, screenCfg)

	err = m.saveSysConfig("save")
	if err != nil {
		return err
	}
	m.markClean()
	return nil
}

func (m *Manager) markClean() {
	logger.Debug("markClean")
	m.monitorMapMu.Lock()
	for _, monitor := range m.monitorMap {
		monitor.PropsMu.Lock()
		monitor.backup = nil
		monitor.changes = nil
		monitor.PropsMu.Unlock()
	}
	m.monitorMapMu.Unlock()

	m.PropsMu.Lock()
	m.setPropHasChanged(false)
	m.PropsMu.Unlock()

	m.futureConfig.clear()
}

type monitorsFutureConfig struct {
	mu         sync.Mutex
	monitorsId monitorsId
	configs    SysMonitorConfigs
}

func (mfc *monitorsFutureConfig) clear() {
	mfc.mu.Lock()
	defer mfc.mu.Unlock()

	mfc.monitorsId = monitorsId{}
	mfc.configs = nil
}

func (mfc *monitorsFutureConfig) setConfigs(monitorsId monitorsId, configs SysMonitorConfigs) {
	mfc.mu.Lock()
	defer mfc.mu.Unlock()

	mfc.monitorsId = monitorsId
	mfc.configs = configs.clone()
}

func (mfc *monitorsFutureConfig) getConfigs(monitorsId monitorsId) SysMonitorConfigs {
	mfc.mu.Lock()
	defer mfc.mu.Unlock()

	if mfc.monitorsId != monitorsId {
		return nil
	}

	return mfc.configs.clone()
}

func (m *Manager) applyChanges() error {
	if m.getInApply() {
		logger.Debug("no apply changes, in apply")
		return nil
	}

	m.PropsMu.RLock()
	if !m.HasChanged {
		m.PropsMu.RUnlock()
		logger.Debug("no apply changes, no changed")
		return nil
	}
	m.PropsMu.RUnlock()

	monitorMap := m.cloneMonitorMap()
	monitors := getConnectedMonitors(monitorMap)
	monitorsId := monitors.getMonitorsId()

	configs := m.getSuitableSysMonitorConfigs(m.DisplayMode, monitorsId, monitors)
	for _, config := range configs {
		monitor := monitors.GetByUuid(config.UUID)
		if monitor == nil {
			continue
		}
		config.modify(monitor.changes)
	}

	err := m.applySysMonitorConfigs(DisplayModeInvalid, monitorsId, monitorMap, configs, nil)
	if err != nil {
		logger.Warning("[applyChanges] apply sys monitor configs failed:", err)
		m.futureConfig.clear()
	} else {
		m.futureConfig.setConfigs(monitorsId, configs)
	}
	return err
}

func (m *Manager) resetChangesWithoutApply() {
	m.PropsMu.Lock()
	if !m.HasChanged {
		m.PropsMu.Unlock()
		return
	}
	m.setPropHasChanged(false)
	m.PropsMu.Unlock()

	m.monitorMapMu.Lock()
	for _, monitor := range m.monitorMap {
		monitor.resetChanges()
	}
	m.monitorMapMu.Unlock()
}

func (m *Manager) getConnectedMonitors() Monitors {
	m.monitorMapMu.Lock()
	defer m.monitorMapMu.Unlock()
	return getConnectedMonitors(m.monitorMap)
}

func (m *Manager) cloneMonitorMap() map[uint32]*Monitor {
	m.monitorMapMu.Lock()
	defer m.monitorMapMu.Unlock()

	return m.cloneMonitorMapNoLock()
}

func (m *Manager) cloneMonitorMapNoLock() map[uint32]*Monitor {
	result := make(map[uint32]*Monitor, len(m.monitorMap))
	for id, monitor := range m.monitorMap {
		result[id] = monitor.clone()
	}
	return result
}

func (m *Manager) applySysMonitorConfigs(mode byte, monitorsId monitorsId, monitorMap map[uint32]*Monitor, configs SysMonitorConfigs, options applyOptions) error {
	if logger.GetLogLevel() == log.LevelDebug {
		logger.Debugf("applySysMonitorConfigs configs: %s, options: %v", spew.Sdump(configs), options)
	}

	// 验证配置
	enabledCount := 0
	for _, config := range configs {
		if config.Enabled {
			enabledCount++
		}
	}
	if enabledCount == 0 {
		return errors.New("invalid configs: no enabled monitor")
	}

	var primaryMonitorID uint32
	var enabledMonitors []*Monitor
	for _, monitor := range monitorMap {
		monitorCfg := configs.getByUuid(monitor.uuid)
		if monitorCfg == nil {
			logger.Debug("disable monitor", monitor)
			monitor.Enabled = false
		} else {
			if monitorCfg.Enabled {
				logger.Debug("enable monitor", monitor)
				if monitorCfg.Primary {
					primaryMonitorID = monitor.ID
				}
				enabledMonitors = append(enabledMonitors, monitor)
				//所有可设置的值都设置为配置文件中的值
				monitor.X = monitorCfg.X
				monitor.Y = monitorCfg.Y
				monitor.Rotation = monitorCfg.Rotation
				monitor.Reflect = monitorCfg.Reflect

				// monitorCfg 中的宽和高是经过 rotation 调整的
				width := monitorCfg.Width
				height := monitorCfg.Height
				swapWidthHeightWithRotation(monitorCfg.Rotation, &width, &height)
				mode := monitor.selectMode(width, height, monitorCfg.RefreshRate)
				monitor.setModeNoEmitChanged(mode)
				monitor.Enabled = true
			} else {
				logger.Debug("disable monitor", monitor)
				monitor.Enabled = false
			}
		}
	}

	if primaryMonitorID == 0 {
		primaryMonitor := m.getDefaultPrimaryMonitor(enabledMonitors)
		if primaryMonitor != nil {
			primaryMonitorID = primaryMonitor.ID
		} else {
			logger.Warningf("failed to get default primary monitor, enabledMonitors: %v", enabledMonitors)
		}
	}

	// 对于 X 来说，这里是处理 crtc 设置
	err := m.apply(monitorsId, monitorMap, options, primaryMonitorID, mode)
	if err != nil {
		monitors := getConnectedMonitors(monitorMap)
		currentMonitorMap := m.cloneMonitorMap()
		currentMonitors := getConnectedMonitors(currentMonitorMap)
		if len(monitors) != len(currentMonitors) {
			return &applyFailed{reason: reasonNumChanged, monitors: currentMonitors}
		}
		return err
	}

	// NOTE: DisplayMode 属性改变信号应该在设置各个 Monitor 的属性之后，否则会引发前端 dcc 的 bug。
	if mode != DisplayModeInvalid {
		m.setPropDisplayMode(mode)
	}

	// 异步处理亮度设置
	go func() {
		for _, config := range configs {
			if config.Enabled && m.canSetBrightness(config.Name) {
				err := m.setBrightness(config.Name, config.Brightness)
				if err != nil {
					logger.Warningf("call setBrightness err: %v, config.Name: %s", err, config.Name)
					monitors := m.getConnectedMonitors()
					monitor := monitors.GetByUuid(config.UUID)
					// 插拔过程中存在异常monitor空
					if monitor == nil {
						logger.Warning("call GetByUuid failed: ", config.UUID)
						continue
					}

					err := m.setBrightness(monitor.Name, config.Brightness)
					if err != nil {
						logger.Warningf("call setBrightness err: %v, monitor.Name: %s", err, monitor.Name)
					}
				}
			}
		}
		m.syncPropBrightness()
	}()

	// NOTE: Primary 和 PrimaryRect 属性改变信号应该在 DisplayMode 属性改变之后，否则会引发前端 dcc 的 bug。
	err = m.mm.setMonitorPrimary(primaryMonitorID)
	if err != nil {
		logger.Warning(err)
	}

	return nil
}

type applyFailed struct {
	reason   string
	err      error
	monitors Monitors
}

const (
	reasonNumChanged = "number of connected monitors changed"
)

func (err *applyFailed) Error() string {
	return fmt.Sprintf("apply failed, reason: %v, original error: %v", err.reason, err.err)
}

func (m *Manager) getDefaultPrimaryMonitor(monitors []*Monitor) *Monitor {
	if len(monitors) == 0 {
		return nil
	}
	builtinMonitor := m.getBuiltinMonitor()
	if builtinMonitor != nil && Monitors(monitors).GetById(builtinMonitor.ID) != nil {
		return builtinMonitor
	}

	monitor := m.getPriorMonitor(monitors)
	return monitor
}

func (m *Manager) getMonitorConnectTime(name string) time.Time {
	m.sysConfig.mu.Lock()
	defer m.sysConfig.mu.Unlock()
	return m.sysConfig.Config.Cache.ConnectTime[name]
}

// getPriorMonitor 获取优先级最高的显示器，用于作为主屏。
func (m *Manager) getPriorMonitor(monitors []*Monitor) *Monitor {
	if len(monitors) == 0 {
		return nil
	}
	sort.Slice(monitors, func(i, j int) bool {
		mi := monitors[i]
		mj := monitors[j]

		pi := getPortPriority(mi.Name)
		pj := getPortPriority(mj.Name)

		// 多字段排序
		// 按优先级从小到大排序，如果优先级相同，按最后连接时间从早到晚排序。
		if pi == pj {
			ti := m.getMonitorConnectTime(mi.Name)
			tj := m.getMonitorConnectTime(mj.Name)
			return ti.Before(tj)
		}
		return pi < pj
	})
	return monitors[0]
}

// getPortType 根据显示器名称判断出端口类型，比如 vga，hdmi，edp 等。
func getPortType(name string) string {
	i := strings.IndexRune(name, '-')
	if i != -1 {
		name = name[0:i]
	}
	return strings.ToLower(name)
}

func getPortPriority(name string) int {
	portType := getPortType(name)
	p, ok := _monitorTypePriority[portType]
	if ok {
		return p
	}
	return priorityOther
}

func (m *Manager) getMonitorsId() monitorsId {
	return getConnectedMonitors(m.cloneMonitorMap()).getMonitorsId()
}

// updatePropMonitors 把所有已连接显示器的对象路径设置到 Manager 的 Monitors 属性。
func (m *Manager) updatePropMonitors() {
	monitors := m.getConnectedMonitors()
	paths := monitors.getPaths()
	logger.Debug("update prop Monitors:", paths)
	m.PropsMu.Lock()
	m.setPropMonitors(paths)
	m.PropsMu.Unlock()
}

func (m *Manager) initTouchscreens() {
	_, err := m.dbusDaemon.ConnectNameOwnerChanged(func(name, oldOwner, newOwner string) {
		if name == m.inputDevices.ServiceName_() && newOwner == "" {
			m.setPropTouchscreens(nil)
			m.setPropTouchscreensV2(nil)
		}
	})
	if err != nil {
		logger.Warning(err)
	}

	_, err = m.inputDevices.ConnectTouchscreenAdded(func(path dbus.ObjectPath) {
		m.tm.refreshDevicesFromDisplayServer()
		err := m.tm.addTouchscreen(path)
		if err != nil {
			logger.Warning(err)
		}

		m.setPropTouchscreens(m.tm.touchscreenList())
		m.setPropTouchscreensV2(m.Touchscreens)
		m.handleTouchscreenChanged()
		m.showTouchscreenDialogs()
	})
	if err != nil {
		logger.Warning(err)
	}

	_, err = m.inputDevices.ConnectTouchscreenRemoved(func(path dbus.ObjectPath) {
		m.tm.removeTouchscreen(path)

		m.setPropTouchscreens(m.tm.touchscreenList())
		m.setPropTouchscreensV2(m.Touchscreens)
		m.handleTouchscreenChanged()
		m.showTouchscreenDialogs()
	})
	if err != nil {
		logger.Warning(err)
	}

	touchscreens, err := m.inputDevices.Touchscreens().Get(0)
	if err != nil {
		logger.Warning(err)
		return
	}

	m.tm.refreshDevicesFromDisplayServer()
	for _, p := range touchscreens {
		err := m.tm.addTouchscreen(p)
		if err != nil {
			logger.Warning(err)
			continue
		}
	}
	m.setPropTouchscreens(m.tm.touchscreenList())
	m.setPropTouchscreensV2(m.Touchscreens)

	m.initTouchMap()
	m.handleTouchscreenChanged()
	m.showTouchscreenDialogs()
}

func (m *Manager) initTouchMap() {
	m.touchscreenMap = make(map[string]touchscreenMapValue)
	m.TouchMap = make(map[string]string)
	m.touchScreenDialogMap = make(map[string]*exec.Cmd)

	value := m.settings.GetString(gsKeyMapOutput)
	if len(value) == 0 {
		return
	}

	err := jsonUnmarshal(value, &m.touchscreenMap)
	if err != nil {
		logger.Warningf("[initTouchMap] unmarshal (%s) failed: %v",
			value, err)
		return
	}

	for touchUUID, v := range m.touchscreenMap {
		for _, t := range m.Touchscreens {
			if t.UUID == touchUUID {
				m.TouchMap[t.UUID] = v.OutputName
				break
			}
		}
	}
}

func (m *Manager) updateTouchscreenMap(outputName string, touchUUID string, auto bool) {
	var err error

	m.touchscreenMap[touchUUID] = touchscreenMapValue{
		OutputName: outputName,
		Auto:       auto,
	}
	m.settings.SetString(gsKeyMapOutput, jsonMarshal(m.touchscreenMap))

	m.TouchMap[touchUUID] = outputName

	err = m.emitPropChangedTouchMap(m.TouchMap)
	if err != nil {
		logger.Warning("failed to emit TouchMap PropChanged:", err)
	}
}

func (m *Manager) removeTouchscreenMap(touchUUID string) {
	delete(m.touchscreenMap, touchUUID)
	m.settings.SetString(gsKeyMapOutput, jsonMarshal(m.touchscreenMap))

	delete(m.TouchMap, touchUUID)

	err := m.emitPropChangedTouchMap(m.TouchMap)
	if err != nil {
		logger.Warning("failed to emit TouchMap PropChanged:", err)
	}
}

func (m *Manager) associateTouch(monitor *Monitor, touchUUID string, auto bool) error {
	m.PropsMu.Lock()
	defer m.PropsMu.Unlock()

	if v, ok := m.touchscreenMap[touchUUID]; ok && v.OutputName == monitor.Name {
		return nil
	}

	err := m.tm.associateTouchscreen(monitor, touchUUID)
	if err != nil {
		logger.Warning("[AssociateTouch] set failed:", err)
		return err
	}

	m.updateTouchscreenMap(monitor.Name, touchUUID, auto)

	return nil
}

func (m *Manager) loadUserConfig() error {
	content, err := ioutil.ReadFile(userConfigFile)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}
	var cfg UserConfig
	err = json.Unmarshal(content, &cfg)
	if err != nil {
		return err
	}
	cfg.fix()
	m.userConfig = cfg
	return nil
}

func (m *Manager) saveUserConfig() error {
	m.userCfgMu.Lock()
	defer m.userCfgMu.Unlock()
	return m.saveUserConfigNoLock()
}

func (m *Manager) saveUserConfigNoLock() error {
	if _greeterMode {
		return nil
	}

	m.userConfig.Version = userConfigVersion
	if logger.GetLogLevel() == log.LevelDebug {
		if m.debugOpts.printSaveCfgDetail {
			logger.Debug("saveUserConfig", spew.Sdump(m.userConfig))
		} else {
			logger.Debug("saveUserConfig")
		}
	}
	content, err := json.Marshal(m.userConfig)
	if err != nil {
		return err
	}
	dir := filepath.Dir(userConfigFile)
	err = os.MkdirAll(dir, 0755)
	if err != nil {
		return err
	}

	filename := userConfigFile + ".new"
	err = ioutil.WriteFile(filename, content, 0644)
	if err != nil {
		return err
	}
	err = os.Rename(filename, userConfigFile)
	return err
}

func (m *Manager) loadSysConfig() {
	cfg, err := m.getSysConfig()
	if err != nil {
		logger.Warning(err)
		// 修正一下空配置
		m.sysConfig.fix()
	} else {
		m.sysConfig.copyFrom(cfg)
	}
}

func (c *SysRootConfig) fix() {
	cfg := &c.Config
	// 默认显示模式为复制模式
	if cfg.DisplayMode == DisplayModeUnknown || cfg.DisplayMode == DisplayModeCustom {
		cfg.DisplayMode = DisplayModeMirror
	}
	for _, screenConfig := range cfg.Screens {
		screenConfig.fix()
	}
}

// 无需对结果再次地调用 fix 方法
func (m *Manager) getSysConfig() (*SysRootConfig, error) {
	cfgJSON, err := m.sysDisplay.GetConfig(0)
	if err != nil {
		return nil, err
	}
	var rootCfg SysRootConfig
	err = jsonUnmarshal(cfgJSON, &rootCfg)
	if err != nil {
		return nil, err
	}
	rootCfg.fix()
	return &rootCfg, nil
}

// saveSysConfig 保存系统级配置
func (m *Manager) saveSysConfig(reason string) error {
	m.sysConfig.mu.Lock()
	defer m.sysConfig.mu.Unlock()

	err := m.saveSysConfigNoLock(reason)
	return err
}

type debugOptions struct {
	printSaveCfgDetail bool
}

func (m *Manager) initDebugOptions() {
	m.debugOpts.printSaveCfgDetail = os.Getenv("DISPLAY_PRINT_SAVE_CFG_DETAIL") == "1"
}

func (m *Manager) saveSysConfigNoLock(reason string) error {
	if _greeterMode {
		return nil
	}

	m.sysConfig.UpdateAt = time.Now().Format(time.RFC3339Nano)
	m.sysConfig.Version = sysConfigVersion

	if logger.GetLogLevel() == log.LevelDebug {
		if m.debugOpts.printSaveCfgDetail {
			logger.Debugf("saveSysConfig reason: %s, sysConfig: %s", reason, spew.Sdump(&m.sysConfig))
		} else {
			logger.Debugf("saveSysConfig reason: %s", reason)
		}
	}

	cfgJSON := jsonMarshal(&m.sysConfig)
	err := m.sysDisplay.SetConfig(0, cfgJSON)
	return err
}

func (m *Manager) setMonitorFillMode(monitor *Monitor, fillMode string) error {
	m.setFillModeMu.Lock()
	defer m.setFillModeMu.Unlock()

	if len(monitor.AvailableFillModes) == 0 {
		return errors.New("monitor do not support set fill mode")
	}

	m.sysConfig.mu.Lock()
	cfg := &m.sysConfig.Config
	fillModeKey := monitor.generateFillModeKey()
	if fillMode == "" {
		fillMode = cfg.FillModes[fillModeKey]
	}
	m.sysConfig.mu.Unlock()
	if fillMode == "" {
		fillMode = fillModeDefault
	}

	logger.Debugf("%v set fill mode %v", monitor, fillMode)

	err := m.mm.setMonitorFillMode(monitor, fillMode)
	if err != nil {
		return err
	}

	m.sysConfig.mu.Lock()
	if cfg.FillModes == nil {
		cfg.FillModes = make(map[string]string)
	}
	cfg.FillModes[fillModeKey] = fillMode
	err = m.saveSysConfigNoLock("fill mode changed")
	m.sysConfig.mu.Unlock()

	return err
}

func (m *Manager) showTouchscreenDialog(touchScreenUUID string) error {
	m.touchScreenDialogMutex.RLock()
	existCmd, ok := m.touchScreenDialogMap[touchScreenUUID]
	m.touchScreenDialogMutex.RUnlock()
	if ok && existCmd != nil {
		// 已经存在dialog，不重复打开dialog
		logger.Debug("showTouchscreenDialog failed, touchScreen is existed:", touchScreenUUID)
		return nil
	}

	cmd := exec.Command(cmdTouchscreenDialogBin, touchScreenUUID)

	err := cmd.Start()
	if err != nil {
		return err
	}

	m.touchScreenDialogMutex.Lock()
	m.touchScreenDialogMap[touchScreenUUID] = cmd
	m.touchScreenDialogMutex.Unlock()

	go func() {
		err = cmd.Wait()
		if err != nil {
			logger.Debug(err)
		}
		m.touchScreenDialogMutex.Lock()
		if _, ok := m.touchScreenDialogMap[touchScreenUUID]; ok {
			delete(m.touchScreenDialogMap, touchScreenUUID)
		}
		m.touchScreenDialogMutex.Unlock()
	}()
	return nil
}

func (m *Manager) handleTouchscreenChanged() {
	logger.Debugf("touchscreens changed %#v", m.Touchscreens)

	monitors := m.getConnectedMonitors()

	// 清除已拔下触摸屏的配置
	for uuid := range m.touchscreenMap {
		found := false
		for _, touch := range m.Touchscreens {
			if touch.UUID == uuid {
				found = true
				break
			}
		}
		if !found {
			m.removeTouchscreenMap(uuid)
		}
	}

	if len(m.Touchscreens) == 1 && len(monitors) == 1 {
		m.associateTouch(monitors[0], m.Touchscreens[0].UUID, true)
	}

	for _, touch := range m.Touchscreens {
		// 有配置，直接使配置生效
		if v, ok := m.touchscreenMap[touch.UUID]; ok {
			monitor := monitors.GetByName(v.OutputName)
			if monitor != nil {
				logger.Debugf("assigned %s to %s, cfg", touch.UUID, v.OutputName)
				err := m.tm.associateTouchscreen(monitor, touch.UUID)
				if err != nil {
					logger.Warning("failed to map touchscreen:", err)
				}
				continue
			}

			// else 配置中的显示器不存在，忽略配置并删除
			m.removeTouchscreenMap(touch.UUID)
		}

		if touch.outputName != "" {
			logger.Debugf("assigned %s to %s, WL_OUTPUT", touch.UUID, touch.outputName)
			monitor := monitors.GetByName(touch.outputName)
			if monitor == nil {
				logger.Warning("WL_OUTPUT not found")
				continue
			}
			err := m.associateTouch(monitor, touch.UUID, true)
			if err != nil {
				logger.Warning(err)
			}
			continue
		}

		// 物理大小匹配
		assigned := false
		for _, monitor := range monitors {
			logger.Debugf("monitor %s w %d h %d, touch %s w %d h %d",
				monitor.Name, monitor.MmWidth, monitor.MmHeight,
				touch.UUID, uint32(math.Round(touch.width)), uint32(math.Round(touch.height)))

			if monitor.MmWidth == uint32(math.Round(touch.width)) && monitor.MmHeight == uint32(math.Round(touch.height)) {
				logger.Debugf("assigned %s to %s, phy size", touch.UUID, monitor.Name)
				err := m.associateTouch(monitor, touch.UUID, true)
				if err != nil {
					logger.Warning(err)
				}
				assigned = true
				break
			}
		}
		if assigned {
			continue
		}

		// 有内置显示器，且触摸屏不是通过 USB 连接，关联内置显示器
		if m.builtinMonitor != nil {
			if touch.busType != busTypeUSB {
				logger.Debugf("assigned %s to %s, builtin", touch.UUID, m.builtinMonitor.Name)
				err := m.associateTouch(m.builtinMonitor, touch.UUID, true)
				if err != nil {
					logger.Warning(err)
				}
				continue
			}
		}

		// 关联主显示器，不保存主显示器不保存配置，并显示配置 Dialog
		monitor := monitors.GetByName(m.Primary)
		if monitor == nil {
			logger.Warningf("primary output %s not found", m.Primary)
		} else {
			err := m.tm.associateTouchscreen(monitor, touch.UUID)
			if err != nil {
				logger.Warning("failed to map touchscreen:", err)
			}
		}
	}
}

/* 根据从内核获取的屏幕的初始状态(屏幕的方向)，旋转桌面到对应的方向 */
func (m *Manager) initScreenRotation() {
	if m.sensorProxy == nil {
		m.sensorProxy = m.sysBus.Object(sensorProxyInterface, sensorProxyPath)
	}

	screenRatationStatus := "normal"
	if m.sensorProxy != nil {
		err := m.sensorProxy.Call(sensorProxyGetScreenStatus, 0).Store(&screenRatationStatus)
		if err != nil {
			logger.Warning("failed to get screen rotation status", err)
			return
		}

		startBuildInScreenRotationMutex.Lock()
		defer startBuildInScreenRotationMutex.Unlock()
		rotationRotate, ok := rotationScreenValue[strings.TrimSpace(screenRatationStatus)]
		if ok {
			m.startBuildInScreenRotation(rotationRotate)
		}
	}
}

// 检查当前连接的所有触控面板, 如果没有映射配置, 那么调用 OSD 弹窗.
func (m *Manager) showTouchscreenDialogs() {
	for _, touch := range m.Touchscreens {
		if _, ok := m.touchscreenMap[touch.UUID]; !ok {
			logger.Debug("cannot find touchscreen", touch.UUID, "'s configure, show OSD")
			err := m.showTouchscreenDialog(touch.UUID)
			if err != nil {
				logger.Warning("shotTouchscreenOSD", err)
			}
		}
	}
}

// syncPropBrightness 将亮度从每个显示器 monitor.Brightness 同步到 Manager 的属性 Brightness 中。
func (m *Manager) syncPropBrightness() {
	monitors := m.getConnectedMonitors()
	newMap := make(map[string]float64)
	for _, monitor := range monitors {
		newMap[monitor.Name] = monitor.Brightness
	}
	m.PropsMu.Lock()
	m.setPropBrightness(newMap)
	m.PropsMu.Unlock()
}

func (m *Manager) getRateFilter() RateFilterMap {
	data := make(RateFilterMap)
	jsonStr := m.settings.GetString(gsKeyRateFilter)
	err := json.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		logger.Warning(err)
		return data
	}

	return data
}

func (m *Manager) listenRotateSignal() {
	systemBus, err := dbus.SystemBus()
	if err != nil {
		logger.Fatal(err)
	}

	err = systemBus.BusObject().AddMatchSignal(sensorProxyInterface, sensorProxySignalName,
		dbus.WithMatchObjectPath(sensorProxyPath), dbus.WithMatchSender(sensorProxyInterface)).Err
	if err != nil {
		logger.Fatal(err)
	}

	signalCh := make(chan *dbus.Signal, 10)
	m.sysBus.Signal(signalCh)
	go func() {
		var rotationScreenTimer *time.Timer
		rotateScreenValue := "normal"

		for sig := range signalCh {
			if sig.Path != sensorProxyPath || sig.Name != sensorProxySignal {
				continue
			}

			err = dbus.Store(sig.Body, &rotateScreenValue)
			if err != nil {
				logger.Warning("call dbus.Store err:", err)
				continue
			}

			if rotationScreenTimer == nil {
				rotationScreenTimer = time.AfterFunc(time.Millisecond*time.Duration(m.rotateScreenTimeDelay), func() {
					startBuildInScreenRotationMutex.Lock()
					defer startBuildInScreenRotationMutex.Unlock()
					rotationRotate, ok := rotationScreenValue[strings.TrimSpace(rotateScreenValue)]
					if ok {
						m.startBuildInScreenRotation(rotationRotate)
					}
				})
			} else {
				rotationScreenTimer.Reset(time.Millisecond * time.Duration(m.rotateScreenTimeDelay))
			}
		}
	}()
}

func (m *Manager) startBuildInScreenRotation(latestRotationValue uint16) {
	// 判断旋转信号值是否符合要求
	if latestRotationValue != randr.RotationRotate0 &&
		latestRotationValue != randr.RotationRotate90 &&
		latestRotationValue != randr.RotationRotate270 {
		logger.Warningf("get Rotation screen value failed: %d", latestRotationValue)
		return
	}

	if m.builtinMonitor != nil {
		err := m.builtinMonitor.SetRotation(latestRotationValue)
		if err != nil {
			logger.Warning("call SetRotation failed:", err)
			return
		}

		// 使旋转后配置生效
		err = m.ApplyChanges()
		if err != nil {
			logger.Warning("call ApplyChanges failed:", err)
			return
		}

		err = m.Save()
		if err != nil {
			logger.Warning("call Save failed:", err)
			return
		}

		m.builtinMonitor.setPropCurrentRotateMode(RotationFinishModeAuto)
	}
}

func (m *Manager) listenSettingsChanged() {
	if m.settings == nil {
		m.rotateScreenTimeDelay = defaultRotateScreenTimeDelay
		return
	}

	gsettings.ConnectChanged(gsSchemaDisplay, "*", func(key string) {
		switch key {
		case gsKeyRotateScreenTimeDelay:
			m.rotateScreenTimeDelay = m.settings.GetInt(key)
			return
		default:
			return
		}
	})
}

// wayland 下专用，更新屏幕宽高属性
func (m *Manager) updateScreenSize() {
	var screenWidth uint16
	var screenHeight uint16

	m.monitorMapMu.Lock()
	for _, monitor := range m.monitorMap {
		monitor.PropsMu.RLock()

		if !monitor.Enabled {
			monitor.PropsMu.RUnlock()
			continue
		}
		if screenWidth < uint16(monitor.X)+monitor.Width {
			screenWidth = uint16(monitor.X) + monitor.Width
		}
		if screenHeight < uint16(monitor.Y)+monitor.Height {
			screenHeight = uint16(monitor.Y) + monitor.Height
		}

		monitor.PropsMu.RUnlock()
	}
	m.monitorMapMu.Unlock()

	m.PropsMu.Lock()
	m.setPropScreenWidth(screenWidth)
	m.setPropScreenHeight(screenHeight)
	m.PropsMu.Unlock()
}

func getLspci() (string, error) {
	cmd := exec.Command("lspci")
	cmd.Env = []string{
		"LC_ALL=C",
	}
	out, err := cmd.Output()
	if err != nil {
		logger.Warning(err)
		return "", err
	} else {
		return string(out), nil
	}
}

func (m *Manager) detectDrmSupportGamma() (bool, error) {
	pciInfo, err := getLspci()
	if err != nil {
		logger.Warning(err)
		return false, err
	}
	pciInfos := strings.Split(pciInfo, "\n")
	for _, info := range pciInfos {
		if strings.Contains(info, "VGA") {
			vgaSupportGamma := true
			for _, drm := range m.unsupportGammaDrmList {
				lowDrm := strings.ToLower(drm)
				lowInfo := strings.ToLower(info)
				if strings.Contains(lowInfo, lowDrm) {
					vgaSupportGamma = false
					break
				}
			}
			if vgaSupportGamma {
				return true, nil
			}
		}
	}
	return false, nil
}
