using ColorControl.Shared.Common; using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Native; using NStandard; using System.ComponentModel; using System.Diagnostics; using System.Text.RegularExpressions; namespace ColorControl.Shared.Contracts; public enum PresetTriggerType { [Description("None")] None = 0, [Description("Startup")] Startup = 1, [Description("Resume")] Resume = 2, [Description("Shutdown")] Shutdown = 3, [Description("Standby")] Standby = 4, [Description("Reserved5")] Reserved5 = 5, [Description("Process switch")] ProcessSwitch = 6, [Description("Screensaver start")] ScreensaverStart = 7, [Description("Screensaver stop")] ScreensaverStop = 8, [Description("Display Change")] DisplayChange = 9, } [Flags] public enum PresetConditionType { [Description("None")] None = 0, [Description("SDR")] SDR = 1, [Description("HDR")] HDR = 2, [Description("Full Screen")] FullScreen = 4, [Description("Notifications Disabled")] NotificationsDisabled = 8, [Description("G-SYNC Disabled")] GsyncDisabled = 16, [Description("G-SYNC Enabled")] GsyncEnabled = 32 } public enum PresetOrder { None = 0, [Description("Name")] ByName = 1, [Description("Last used")] ByLastUsed = 2 } public class PresetTrigger { public PresetTriggerType Trigger { get; set; } public List IncludedProcesses { get; set; } public List ExcludedProcesses { get; set; } public string ConnectedDisplaysRegex { get; set; } public PresetConditionType Conditions { get; set; } public string IncludedProcessesAsString { get => IncludedProcesses?.Join(", "); set { IncludedProcesses ??= new List(); Utils.ParseWords(IncludedProcesses, value); } } public string ExcludedProcessesAsString { get => ExcludedProcesses?.Join(", "); set { ExcludedProcesses ??= new List(); Utils.ParseWords(ExcludedProcesses, value); } } public PresetTrigger() { IncludedProcesses = new List(); ExcludedProcesses = new List(); } public bool TriggerActive(PresetTriggerContext context) { var active = Conditions == PresetConditionType.None || (!Conditions.HasFlag(PresetConditionType.SDR) || !context.IsHDRActive) && (!Conditions.HasFlag(PresetConditionType.HDR) || context.IsHDRActive) && (!Conditions.HasFlag(PresetConditionType.GsyncDisabled) || !context.IsGsyncActive) && (!Conditions.HasFlag(PresetConditionType.GsyncEnabled) || context.IsGsyncActive); active = active && context.Triggers.Contains(Trigger); if (!ConnectedDisplaysRegex.IsNullOrWhiteSpace()) { active = active && CCD.EnumerateDisplayDeviceNames().Any(s => { var extendedDisplayName = CCD.GetDisplayInfo(s)?.ExtendedName; return extendedDisplayName is not null && Regex.IsMatch(extendedDisplayName, ConnectedDisplaysRegex); }); } if (Trigger == PresetTriggerType.ProcessSwitch) { var allProcesses = IncludedProcesses.Contains("*"); active = active && (allProcesses || (context.ChangedProcesses?.Any() ?? false)); if (active) { var included = allProcesses || context.ChangedProcesses.Any(cp => IncludedProcesses.Any(ip => cp.ProcessName.NormEquals(ip))); var excluded = context.ChangedProcesses.Any(cp => ExcludedProcesses.Any(ep => cp.ProcessName.NormEquals(ep))); var screenSizeCheck = (!Conditions.HasFlag(PresetConditionType.FullScreen) && !context.ForegroundProcessIsFullScreen) || (context.ForegroundProcess != null && context.ForegroundProcessIsFullScreen && (allProcesses || IncludedProcesses.Any(ip => context.ForegroundProcess.ProcessName.NormEquals(ip)))); var notificationsDisabledCheck = !Conditions.HasFlag(PresetConditionType.NotificationsDisabled) || context.IsNotificationDisabled; active = included && !excluded && screenSizeCheck && notificationsDisabledCheck; } } else if (Trigger == PresetTriggerType.ScreensaverStart || Trigger == PresetTriggerType.ScreensaverStop) { active = active && ((Trigger == PresetTriggerType.ScreensaverStart && context.ScreenSaverTransitionState == ScreenSaverTransitionState.Started) || (Trigger == PresetTriggerType.ScreensaverStop && context.ScreenSaverTransitionState == ScreenSaverTransitionState.Stopped)); } return active; } public override string ToString() { if (Trigger == PresetTriggerType.None) { return string.Empty; } var text = $"On {Trigger.GetDescription()}"; if (Trigger == PresetTriggerType.ProcessSwitch) { text += $"of {DisplayProcesses(IncludedProcesses)}{(ExcludedProcesses.Any() ? ", excluding " + DisplayProcesses(ExcludedProcesses) : string.Empty)}"; } text += $"{(Conditions > 0 ? ", only in " + string.Join(", ", Utils.GetDescriptions((int)Conditions)) : string.Empty)}"; text += ConnectedDisplaysRegex.IsNullOrWhiteSpace() ? "" : $", connected display name matching {ConnectedDisplaysRegex}"; return text; } public static string DisplayProcesses(IEnumerable processes) { return processes.Contains("*") ? "all processes" : string.Join(", ", processes); } internal void Update(PresetTrigger updatedTrigger) { Trigger = updatedTrigger.Trigger; Conditions = updatedTrigger.Conditions; IncludedProcesses ??= []; ExcludedProcesses ??= []; Utils.ParseWords(IncludedProcesses, updatedTrigger.IncludedProcessesAsString); Utils.ParseWords(ExcludedProcesses, updatedTrigger.ExcludedProcessesAsString); ConnectedDisplaysRegex = updatedTrigger.ConnectedDisplaysRegex; } } public class PresetTriggerContext { public IEnumerable Triggers { get; set; } = new[] { PresetTriggerType.ProcessSwitch }; public bool IsHDRActive { get; set; } public bool IsGsyncActive { get; set; } public Process ForegroundProcess { get; set; } public bool ForegroundProcessIsFullScreen { get; set; } public List ChangedProcesses { get; set; } public bool IsNotificationDisabled { get; set; } public ScreenSaverTransitionState ScreenSaverTransitionState { get; set; } } public abstract class PresetBase { public string name { get; set; } public string shortcut { get; set; } public List Triggers { get; set; } public List Steps { get; set; } public string Description { get; set; } public bool ShowInQuickAccess { get; set; } public DateTime? LastUsed { get; set; } public string IdOrName => name.IsNullOrEmpty() ? _id.ToString() : name; private int _id; protected PresetBase() { Triggers = []; Steps = []; } public int id { get { return _id; } set { if (value == 0 /*|| ids.Contains(value)*/) { value = GetNewId(); } else { ids.Add(value); } _id = value; } } public void SetId(int id) { _id = id; } public static List ids = new List(); public static int GetNewId() { int id; do { id = new Random().Next(); } while (ids.Contains(id)); ids.Add(id); return id; } public void SetCloneValues() { _id = 0; if (!string.IsNullOrEmpty(name)) { name += " (copy)"; } } public abstract List GetDisplayValues(Config config = null); public virtual string GetTextForMenuItem() { return name; } public void UpdateTrigger(PresetTriggerType triggerType, PresetConditionType conditions, string includedProcesses = null, string excludedProcesses = null, string connectedDisplaysRegex = null) { if (!Triggers.Any()) { Triggers.Add(new PresetTrigger()); } var trigger = Triggers.First(); trigger.Trigger = triggerType; trigger.Conditions = conditions; if (trigger.IncludedProcesses == null) { trigger.IncludedProcesses = new List(); } if (trigger.ExcludedProcesses == null) { trigger.ExcludedProcesses = new List(); } Utils.ParseWords(trigger.IncludedProcesses, includedProcesses); Utils.ParseWords(trigger.ExcludedProcesses, excludedProcesses); trigger.ConnectedDisplaysRegex = connectedDisplaysRegex; } public void UpdateTriggers(List updatedTriggers) { Triggers.Clear(); foreach (var updatedTrigger in updatedTriggers) { var newTrigger = new PresetTrigger(); newTrigger.Update(updatedTrigger); Triggers.Add(newTrigger); } } public void SetSteps(List steps) { Steps = steps; } }