From 94313662209ff1e6fa20120ca8902ef785474334 Mon Sep 17 00:00:00 2001 From: Codectory <61698721+Codectory@users.noreply.github.com> Date: Mon, 13 Dec 2021 00:16:14 +0100 Subject: [PATCH] 1.7.17 [Changes] - More monitor information [Bug fixes} - Application crashing? #61 - Closing applications didn't worked properly --- .../HDRController/HDRController.cpp | 76 ++++++--- Source/HDRProfile/AutoHDR.csproj | 3 + Source/HDRProfile/Costura64/HDRController.dll | Bin 98816 -> 97280 bytes .../DispatchingObservableCollection.cs | 143 +++++++++++++++++ Source/HDRProfile/Displays/Display.cs | 38 +++-- .../HDRProfile/Displays/DisplayInformation.cs | 27 ++++ Source/HDRProfile/Displays/DisplayInterop.cs | 10 +- Source/HDRProfile/Displays/DisplayManager.cs | 147 ++++++++++-------- Source/HDRProfile/Displays/HDRController.cs | 3 +- .../Profiles/Actions/CloseProgramAction.cs | 3 +- .../ProjectResources/Locale_Texts.Designer.cs | 27 ++++ .../ProjectResources/Locale_Texts.de.resx | 9 ++ .../ProjectResources/Locale_Texts.resx | 9 ++ Source/HDRProfile/Properties/AssemblyInfo.cs | 4 +- Source/HDRProfile/UWP/UWPAppsManager.cs | 6 +- Source/HDRProfile/UserAppSettings.cs | 12 +- Source/HDRProfile/Views/AutoHDRMainView.xaml | 3 +- .../HDRProfile/Views/DisplayManagerView.xaml | 48 ++++-- 18 files changed, 437 insertions(+), 131 deletions(-) create mode 100644 Source/HDRProfile/DispatchingObservableCollection.cs create mode 100644 Source/HDRProfile/Displays/DisplayInformation.cs diff --git a/Source/HDRController/HDRController/HDRController.cpp b/Source/HDRController/HDRController/HDRController.cpp index 410fa41..c2ca9b3 100644 --- a/Source/HDRController/HDRController/HDRController.cpp +++ b/Source/HDRController/HDRController/HDRController.cpp @@ -202,47 +202,77 @@ static void SetHDR(UINT32 uid, bool enabled) static SIZE _GetResolution(UINT32 uid) { + + + uint8_t set[] = { 0x0A, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x81, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }; + + uint8_t request[] = { 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x7C, 0x6F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0xDB, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00 }; + SIZE resolution = SIZE(); + bool returnValue = false; + uint32_t pathCount, modeCount; - UINT32 numPathArrayElements = 0, numModeInfoArrayElements = 0; - UINT32 filter = QDC_ALL_PATHS; + if (ERROR_SUCCESS == GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount)) { + DISPLAYCONFIG_PATH_INFO* pathsArray = nullptr; + DISPLAYCONFIG_MODE_INFO* modesArray = nullptr; const size_t sizePathsArray = pathCount * sizeof(DISPLAYCONFIG_PATH_INFO); const size_t sizeModesArray = modeCount * sizeof(DISPLAYCONFIG_MODE_INFO); + pathsArray = static_cast(std::malloc(sizePathsArray)); + modesArray = static_cast(std::malloc(sizeModesArray)); - DISPLAYCONFIG_PATH_INFO* pathsArray = new DISPLAYCONFIG_PATH_INFO[pathCount]; - DISPLAYCONFIG_MODE_INFO* modesArray = new DISPLAYCONFIG_MODE_INFO[modeCount]; - + if (pathsArray != nullptr && modesArray != nullptr) + { + std::memset(pathsArray, 0, sizePathsArray); + std::memset(modesArray, 0, sizeModesArray); - ZeroMemory(pathsArray, sizeof(DISPLAYCONFIG_PATH_INFO) * pathCount); - ZeroMemory(modesArray, sizeof(DISPLAYCONFIG_MODE_INFO) * modeCount); - QueryDisplayConfig(filter, &pathCount, pathsArray, &modeCount, modesArray, NULL); + if (ERROR_SUCCESS == QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, pathsArray, + &modeCount, modesArray, 0)) + { + DISPLAYCONFIG_DEVICE_INFO_HEADER* setPacket = + reinterpret_cast(set); + DISPLAYCONFIG_DEVICE_INFO_HEADER* requestPacket = + reinterpret_cast(request); + //HDR is off + returnValue = false; + for (int i = 0; i < modeCount; i++) + { + try + { + if (modesArray[i].id == uid) + { + setPacket->adapterId.HighPart = modesArray[i].adapterId.HighPart; + setPacket->adapterId.LowPart = modesArray[i].adapterId.LowPart; + setPacket->id = modesArray[i].id; - for (short i = 0; i < pathCount; i++) - { - try - { - int ix = pathsArray[i].sourceInfo.modeInfoIdx; //assuming path[0] is primary + requestPacket->adapterId.HighPart = modesArray[i].adapterId.HighPart; + requestPacket->adapterId.LowPart = modesArray[i].adapterId.LowPart; + requestPacket->id = modesArray[i].id; + DISPLAYCONFIG_MODE_INFO mode = modesArray[i]; + resolution.cx = mode.sourceMode.width; + resolution.cy = mode.sourceMode.height; + } + } + catch (const std::exception&) + { - if (modesArray[ix].id != uid) + } - { - resolution.cx = modesArray[ix].sourceMode.width; - resolution.cy = modesArray[ix].sourceMode.height; - SetDisplayConfig(pathCount, pathsArray, modeCount, modesArray, SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_ALLOW_CHANGES | SDC_SAVE_TO_DATABASE); } } - catch (const std::exception&) - { - - } + std::free(pathsArray); + std::free(modesArray); + return resolution; } } - return resolution; + } static bool HDRIsOn(UINT32 uid) diff --git a/Source/HDRProfile/AutoHDR.csproj b/Source/HDRProfile/AutoHDR.csproj index 90590fe..20cd9c6 100644 --- a/Source/HDRProfile/AutoHDR.csproj +++ b/Source/HDRProfile/AutoHDR.csproj @@ -175,11 +175,14 @@ Externals\Windows.winmd + False + + diff --git a/Source/HDRProfile/Costura64/HDRController.dll b/Source/HDRProfile/Costura64/HDRController.dll index a26c6292c06c2dabb672435a675c6a416f4d3117..5f1c6585c9d91ff7dd291342e039e77c395801dc 100644 GIT binary patch delta 34939 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 diff --git a/Source/HDRProfile/DispatchingObservableCollection.cs b/Source/HDRProfile/DispatchingObservableCollection.cs new file mode 100644 index 0000000..2dd209c --- /dev/null +++ b/Source/HDRProfile/DispatchingObservableCollection.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Threading; + +namespace AutoHDR +{ + /// + /// This class is an observablecollection which invokes automatically. + /// This means that any change will be done in the right thread. + /// + /// The type of the elements + public class DispatchingObservableCollection : ObservableCollection + { + /// + /// The default constructor of the ObservableCollection + /// + public DispatchingObservableCollection() + { + //Assign the current Dispatcher (owner of the collection) + _currentDispatcher = Dispatcher.CurrentDispatcher; + } + + private readonly Dispatcher _currentDispatcher; + + /// + /// Executes this action in the right thread + /// + ///The action which should be executed + private void DoDispatchedAction(Action action) + { + if (_currentDispatcher.CheckAccess()) + action.Invoke(); + else + _currentDispatcher.Invoke(DispatcherPriority.DataBind, action); + } + + /// + /// Clears all items + /// + protected override void ClearItems() + { + DoDispatchedAction(BaseClearItems); + } + + private void BaseClearItems() + { + base.ClearItems(); + } + + /// + /// Inserts a item at the specified index + /// + ///The index where the item should be inserted + ///The item which should be inserted + protected override void InsertItem(int index, T item) + { + DoDispatchedAction(() => BaseInsertItem(index, item)); + } + + private void BaseInsertItem(int index, T item) + { + base.InsertItem(index, item); + } + + /// + /// Moves an item from one index to another + /// + ///The index of the item which should be moved + ///The index where the item should be moved + protected override void MoveItem(int oldIndex, int newIndex) + { + DoDispatchedAction(() => BaseMoveItem(oldIndex, newIndex)); + } + + private void BaseMoveItem(int oldIndex, int newIndex) + { + base.MoveItem(oldIndex, newIndex); + } + + /// + /// Removes the item at the specified index + /// + ///The index of the item which should be removed + protected override void RemoveItem(int index) + { + DoDispatchedAction(() => BaseRemoveItem(index)); + } + + private void BaseRemoveItem(int index) + { + base.RemoveItem(index); + } + + /// + /// Sets the item at the specified index + /// + ///The index which should be set + ///The new item + protected override void SetItem(int index, T item) + { + DoDispatchedAction(() => BaseSetItem(index, item)); + } + + private void BaseSetItem(int index, T item) + { + base.SetItem(index, item); + } + + /// + /// Fires the CollectionChanged Event + /// + ///The additional arguments of the event + protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + DoDispatchedAction(() => BaseOnCollectionChanged(e)); + } + + private void BaseOnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + base.OnCollectionChanged(e); + } + + /// + /// Fires the PropertyChanged Event + /// + ///The additional arguments of the event + protected override void OnPropertyChanged(PropertyChangedEventArgs e) + { + DoDispatchedAction(() => BaseOnPropertyChanged(e)); + } + + private void BaseOnPropertyChanged(PropertyChangedEventArgs e) + { + base.OnPropertyChanged(e); + } + } +} diff --git a/Source/HDRProfile/Displays/Display.cs b/Source/HDRProfile/Displays/Display.cs index d4fc66e..b5ca371 100644 --- a/Source/HDRProfile/Displays/Display.cs +++ b/Source/HDRProfile/Displays/Display.cs @@ -14,18 +14,30 @@ namespace AutoHDR.Displays [JsonObject(MemberSerialization.OptIn)] public class Display : BaseViewModel { - public static readonly Display AllDisplays = new Display(ProjectResources.Locale_Texts.AllDisplays, UInt32.MaxValue, UInt32.MaxValue, new Size(0, 0),0,0); + public static readonly Display AllDisplays = new Display(ProjectResources.Locale_Texts.AllDisplays, UInt32.MaxValue); private bool _managed = true; [JsonProperty] public bool Managed { get => _managed; set { _managed = value; OnPropertyChanged(); } } + private bool _isPrimary; + + [JsonProperty] + public bool IsPrimary { get => _isPrimary; set { _isPrimary = value; OnPropertyChanged(); } } + private string _name; [JsonProperty] public string Name { get => _name; set { _name = value; OnPropertyChanged(); } } + private string _graphicsCard; + + public string GraphicsCard { get => _graphicsCard; set { _graphicsCard = value; OnPropertyChanged(); } } + + private string _deviceKey; + + public string DeviceKey { get => _deviceKey; set { _deviceKey = value; OnPropertyChanged(); } } private UInt32 _uid; @@ -35,7 +47,7 @@ public class Display : BaseViewModel private uint _id; [JsonProperty] - public uint ID { get => _id; private set { _id = value; OnPropertyChanged(); } } + public uint ID { get => _id; set { _id = value; OnPropertyChanged(); } } private bool _hdrState; @@ -61,14 +73,22 @@ private Display() } - public Display(string name, uint uID, uint id, Size resolution, int refreshRate, int colorDepth) + public Display(DisplayInformation displayInformation, uint uid) + { + Name = displayInformation.DisplayDevice.DeviceName; + UID = uid; + ID = displayInformation.Id; + IsPrimary = displayInformation.IsPrimary; + DeviceKey = displayInformation.DisplayDevice.DeviceKey; + Resolution = new Size(displayInformation.Devmode.dmPelsWidth, displayInformation.Devmode.dmPelsHeight); + RefreshRate = displayInformation.Devmode.dmDisplayFrequency; + GraphicsCard = displayInformation.DisplayDevice.DeviceString; + } + + public Display(string name, uint uid) { - Name = name ?? throw new ArgumentNullException(nameof(name)); - UID = uID; - ID = id; - Resolution = resolution; - RefreshRate = refreshRate; - ColorDepth = colorDepth; + Name = name; + UID = uid; } public void UpdateHDRState() diff --git a/Source/HDRProfile/Displays/DisplayInformation.cs b/Source/HDRProfile/Displays/DisplayInformation.cs new file mode 100644 index 0000000..3411693 --- /dev/null +++ b/Source/HDRProfile/Displays/DisplayInformation.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AutoHDR.Displays +{ + public class DisplayInformation + { + public uint Id { get; private set; } + public DISPLAY_DEVICE DisplayDevice { get; private set; } + public DEVMODE Devmode { get; private set; } + public bool IsPrimary => DisplayDevice.StateFlags.HasFlag(DisplayDeviceStateFlags.PrimaryDevice); + + public DisplayInformation(uint id, DISPLAY_DEVICE displayDevice, DEVMODE devmode) : this(id, displayDevice) + { + Devmode = devmode; + } + + public DisplayInformation(uint id, DISPLAY_DEVICE displayDevice) + { + Id = id; + DisplayDevice = displayDevice; + } + } +} diff --git a/Source/HDRProfile/Displays/DisplayInterop.cs b/Source/HDRProfile/Displays/DisplayInterop.cs index ce5a921..43d5ce6 100644 --- a/Source/HDRProfile/Displays/DisplayInterop.cs +++ b/Source/HDRProfile/Displays/DisplayInterop.cs @@ -29,7 +29,7 @@ internal static extern int EnumDisplaySettings( } [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)] - internal struct DEVMODE + public struct DEVMODE { public const int CCHDEVICENAME = 32; public const int CCHFORMNAME = 32; @@ -102,7 +102,7 @@ internal struct DEVMODE } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal struct DISPLAY_DEVICE + public struct DISPLAY_DEVICE { [MarshalAs(UnmanagedType.U4)] public int cb; @@ -119,7 +119,7 @@ internal struct DISPLAY_DEVICE } [StructLayout(LayoutKind.Sequential)] - struct POINTL + public struct POINTL { long x; long y; @@ -138,7 +138,7 @@ enum DISP_CHANGE : int } [Flags()] - enum DisplayDeviceStateFlags : int + public enum DisplayDeviceStateFlags : int { AttachedToDesktop = 0x1, MultiDriver = 0x2, @@ -169,7 +169,7 @@ enum DisplaySettingsFlags : int } [Flags()] - enum DM : int + public enum DM : int { Orientation = 0x1, PaperSize = 0x2, diff --git a/Source/HDRProfile/Displays/DisplayManager.cs b/Source/HDRProfile/Displays/DisplayManager.cs index 2d5b69f..84430c2 100644 --- a/Source/HDRProfile/Displays/DisplayManager.cs +++ b/Source/HDRProfile/Displays/DisplayManager.cs @@ -12,12 +12,12 @@ using System.Text; using System.Threading; +using System.Windows.Threading; namespace AutoHDR.Displays { public class DisplayManager : BaseViewModel { - Thread _updateThread = null; readonly object _threadControlLock = new object(); bool _monitorCancelRequested = false; @@ -36,7 +36,7 @@ private DisplayManager() public bool Monitoring { get; private set; } = false; - public UserAppSettings Settings { get; private set; } + public UserAppSettings Settings { get; private set; } public ObservableCollection Monitors => Settings.Monitors; @@ -54,6 +54,7 @@ public void StartMonitoring() if (Monitoring) return; _updateThread = new Thread(UpdateMonitorLoop); + _updateThread.SetApartmentState(ApartmentState.STA); _updateThread.IsBackground = true; Monitoring = true; _monitorCancelRequested = false; @@ -78,24 +79,35 @@ private void UpdateMonitorLoop() { while (!_monitorCancelRequested) { - bool currentValue = false; - MergeMonitors(GetActiveMonitors()); - foreach (Display monitor in Monitors) + try { - monitor.UpdateHDRState(); - if (monitor.Managed) - currentValue = currentValue || monitor.HDRState; - monitor.Resolution = GetResolution(monitor.ID); - monitor.RefreshRate = GetRefreshRate(monitor.ID); - + bool currentValue = false; + Dispatcher.CurrentDispatcher.Invoke(() => + { + MergeMonitors(GetActiveMonitors()); + }); + foreach (Display monitor in Monitors) + { + monitor.UpdateHDRState(); + if (monitor.Managed) + currentValue = currentValue || monitor.HDRState; + monitor.Resolution = GetResolution(monitor.UID); + monitor.RefreshRate = GetRefreshRate(monitor.ID); + + } + bool changed = GlobalHDRIsActive != currentValue; + GlobalHDRIsActive = currentValue; + if (changed) + { + try { HDRIsActiveChanged?.Invoke(null, EventArgs.Empty); } catch { } + } + System.Threading.Thread.Sleep(100); } - bool changed = GlobalHDRIsActive != currentValue; - GlobalHDRIsActive = currentValue; - if (changed) + catch (Exception ex) { - try { HDRIsActiveChanged?.Invoke(null, EventArgs.Empty); } catch { } + Globals.Logs.AddException(ex); + throw; } - System.Threading.Thread.Sleep(100); } } @@ -112,8 +124,8 @@ private void ChangeDisplaySetting(uint deviceID, Func func) d.DeviceName, NativeMethods.ENUM_CURRENT_SETTINGS, ref dm)) { - dm= func.Invoke(dm); - + dm = func.Invoke(dm); + DISP_CHANGE iRet = NativeMethods.ChangeDisplaySettingsEx( d.DeviceName, ref dm, IntPtr.Zero, DisplaySettingsFlags.CDS_UPDATEREGISTRY, IntPtr.Zero); @@ -198,7 +210,6 @@ public int GetRefreshRate(uint deviceID) DEVMODE dm = new DEVMODE(); d.cb = Marshal.SizeOf(d); - NativeMethods.EnumDisplayDevices(null, deviceID, ref d, 0); if (0 != NativeMethods.EnumDisplaySettings( @@ -210,42 +221,37 @@ public int GetRefreshRate(uint deviceID) else return 0; } - - public static List GetActiveMonitors() + public static List GetActiveMonitors() { List monitors = new List(); - DisplayConfigTopologyId topologyId; var pathWraps = GetPathWraps(QueryDisplayFlags.OnlyActivePaths, out topologyId); + List _interopDisplays = new List(); + DISPLAY_DEVICE d = new DISPLAY_DEVICE(); + DEVMODE dm = new DEVMODE(); + d.cb = Marshal.SizeOf(d); + + uint deviceID = 0; + while (NativeMethods.EnumDisplayDevices(null, deviceID, ref d, 0)) + { + if (0 != NativeMethods.EnumDisplaySettings(d.DeviceName, NativeMethods.ENUM_CURRENT_SETTINGS, ref dm)) + _interopDisplays.Add(new DisplayInformation(deviceID, d, dm)); + else + _interopDisplays.Add(new DisplayInformation(deviceID, d)); + deviceID++; + } + foreach (var pathWrap in pathWraps) { var path = pathWrap.Path; - var sourceModeInfo = pathWrap.Modes.First(x => x.infoType == DisplayConfigModeInfoType.Source); - - var resolution = new Size - { - Width = sourceModeInfo.sourceMode.width, - Height = sourceModeInfo.sourceMode.height - }; - int colorDepth = 0; - var refreshRate = - (int)Math.Round((double)path.targetInfo.refreshRate.numerator / path.targetInfo.refreshRate.denominator); - var rotationOriginal = path.targetInfo.rotation; - - - DisplayConfigSourceDeviceName displayConfigSourceDeviceName; - - var displayName = ""; - var nameStatus = GetDisplayConfigSourceDeviceName(sourceModeInfo, - out displayConfigSourceDeviceName); - - if (nameStatus == StatusCode.Success) - displayName = displayConfigSourceDeviceName.viewGdiDeviceName; + DisplayInformation displayInformation = _interopDisplays.FirstOrDefault(di => di.Id.Equals(path.sourceInfo.id)); - Display monitor = new Display(displayName, path.targetInfo.id, sourceModeInfo.id, resolution, refreshRate, colorDepth); - monitors.Add(monitor); + Display display = new Display(displayInformation, path.targetInfo.id); + if (!monitors.Any(m => m.ID.Equals(display.ID))) + monitors.Add(display); } + return monitors; } @@ -253,30 +259,42 @@ public static List GetActiveMonitors() private void MergeMonitors(List activeMonitors) { - List toRemove = new List(); - foreach (Display monitor in Monitors) - { - if (!activeMonitors.Any(m => m.UID.Equals(monitor.UID))) - toRemove.Add(monitor); - } - foreach (Display monitor in toRemove) - Monitors.Remove(monitor); - foreach (Display monitor in activeMonitors) + try { - if (!Settings.Monitors.Any(m => m.UID.Equals(monitor.UID))) - Settings.Monitors.Add(monitor); - else + List toRemove = new List(); + foreach (Display monitor in Monitors) + { + if (!activeMonitors.Any(m => m.UID.Equals(monitor.UID))) + toRemove.Add(monitor); + } + foreach (Display monitor in toRemove) + Monitors.Remove(monitor); + foreach (Display monitor in activeMonitors) { - Display existingMonitor = Monitors.First(m => m.UID.Equals(monitor.UID)); - existingMonitor.Name = monitor.Name; - existingMonitor.ColorDepth = monitor.ColorDepth; - existingMonitor.RefreshRate = monitor.RefreshRate; - existingMonitor.Resolution = monitor.Resolution; + if (!Settings.Monitors.Any(m => m.UID.Equals(monitor.UID))) + Settings.Monitors.Add(monitor); + else + { + Display existingMonitor = Monitors.First(m => m.UID.Equals(monitor.UID)); + existingMonitor.Name = monitor.Name; + existingMonitor.ColorDepth = monitor.ColorDepth; + existingMonitor.RefreshRate = monitor.RefreshRate; + existingMonitor.Resolution = monitor.Resolution; + existingMonitor.DeviceKey = monitor.DeviceKey; + existingMonitor.GraphicsCard = monitor.GraphicsCard; + existingMonitor.ID = monitor.ID; + existingMonitor.IsPrimary = monitor.IsPrimary; + + } } } + catch (Exception ex) + { + Globals.Logs.AddException(ex); + } } - + public void ActivateHDR() @@ -401,8 +419,5 @@ private static StatusCode GetDisplayConfigSourceDeviceName( }; return Wrapper.DisplayConfigGetDeviceInfo(ref displayConfigSourceDeviceName); } - } } - - diff --git a/Source/HDRProfile/Displays/HDRController.cs b/Source/HDRProfile/Displays/HDRController.cs index d220af8..b1edcf9 100644 --- a/Source/HDRProfile/Displays/HDRController.cs +++ b/Source/HDRProfile/Displays/HDRController.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using System.Runtime.InteropServices; +using System.Drawing; namespace AutoHDR.Displays { @@ -27,7 +28,7 @@ public static class HDRController [DllImport("HDRController.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern bool GetResolution(UInt32 uid); + public static extern Size GetResolution(UInt32 uid); } } diff --git a/Source/HDRProfile/Profiles/Actions/CloseProgramAction.cs b/Source/HDRProfile/Profiles/Actions/CloseProgramAction.cs index 8bf16c7..953a8c4 100644 --- a/Source/HDRProfile/Profiles/Actions/CloseProgramAction.cs +++ b/Source/HDRProfile/Profiles/Actions/CloseProgramAction.cs @@ -32,7 +32,6 @@ public class CloseProgramAction : ProfileActionBase public bool Force { get => _force; set { _force = value; OnPropertyChanged(); } } - public override string ActionDescription => $"{Locale_Texts.Close} {ProcessName}"; public RelayCommand GetFileCommand { get; private set; } @@ -53,7 +52,7 @@ public override ActionEndResult RunAction(params object[] parameter) CallNewLog(new LogEntry($"Searching for{ProcessName}...")); string searchName = ProcessName; if (searchName.ToUpperInvariant().EndsWith(".EXE")) - searchName.Substring(0, searchName.Length - 4); + searchName = searchName.Substring(0, searchName.Length - 4); foreach (Process process in runningProcesses) { if (process.ProcessName == searchName) diff --git a/Source/HDRProfile/ProjectResources/Locale_Texts.Designer.cs b/Source/HDRProfile/ProjectResources/Locale_Texts.Designer.cs index 86da6ba..2cbef3b 100644 --- a/Source/HDRProfile/ProjectResources/Locale_Texts.Designer.cs +++ b/Source/HDRProfile/ProjectResources/Locale_Texts.Designer.cs @@ -384,6 +384,15 @@ public static string DeviceID { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die UID ähnelt. + /// + public static string DeviceUID { + get { + return ResourceManager.GetString("DeviceUID", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Display ähnelt. /// @@ -501,6 +510,15 @@ public static string GlobalAutoHDR { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Graphics card ähnelt. + /// + public static string GraphicsCard { + get { + return ResourceManager.GetString("GraphicsCard", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die HDR ähnelt. /// @@ -546,6 +564,15 @@ public static string InputDevice { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Primary ähnelt. + /// + public static string IsPrimaryMonitor { + get { + return ResourceManager.GetString("IsPrimaryMonitor", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Last action ähnelt. /// diff --git a/Source/HDRProfile/ProjectResources/Locale_Texts.de.resx b/Source/HDRProfile/ProjectResources/Locale_Texts.de.resx index 7554d5f..7e9dadd 100644 --- a/Source/HDRProfile/ProjectResources/Locale_Texts.de.resx +++ b/Source/HDRProfile/ProjectResources/Locale_Texts.de.resx @@ -219,6 +219,9 @@ Geräte ID + + UID + Displayaktion @@ -252,6 +255,9 @@ Automatischer HDR-Modus für alle Monitore verwenden + + Grafikkarte + HDR @@ -267,6 +273,9 @@ Eingangsgerät + + Hauptmonitor + Letzte Aktion diff --git a/Source/HDRProfile/ProjectResources/Locale_Texts.resx b/Source/HDRProfile/ProjectResources/Locale_Texts.resx index 0a2c0f6..e423fcc 100644 --- a/Source/HDRProfile/ProjectResources/Locale_Texts.resx +++ b/Source/HDRProfile/ProjectResources/Locale_Texts.resx @@ -225,6 +225,9 @@ Device ID + + UID + Display @@ -264,6 +267,9 @@ Use automated HDR Mode for all monitors + + Graphics card + HDR @@ -279,6 +285,9 @@ Input device + + Primary + Last action diff --git a/Source/HDRProfile/Properties/AssemblyInfo.cs b/Source/HDRProfile/Properties/AssemblyInfo.cs index fffe92f..20eff7d 100644 --- a/Source/HDRProfile/Properties/AssemblyInfo.cs +++ b/Source/HDRProfile/Properties/AssemblyInfo.cs @@ -52,5 +52,5 @@ // Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, // indem Sie "*" wie unten gezeigt eingeben: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.7.16.0")] -[assembly: AssemblyFileVersion("1.7.16.0")] +[assembly: AssemblyVersion("1.7.17.0")] +[assembly: AssemblyFileVersion("1.7.17.0")] diff --git a/Source/HDRProfile/UWP/UWPAppsManager.cs b/Source/HDRProfile/UWP/UWPAppsManager.cs index 97966ec..1f6fef0 100644 --- a/Source/HDRProfile/UWP/UWPAppsManager.cs +++ b/Source/HDRProfile/UWP/UWPAppsManager.cs @@ -7,11 +7,9 @@ using System.Management.Automation; using System.Security.Permissions; using System.Security.Principal; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using Windows.ApplicationModel; + using Windows.Management.Deployment; +using Windows.ApplicationModel; namespace AutoHDR.UWP { diff --git a/Source/HDRProfile/UserAppSettings.cs b/Source/HDRProfile/UserAppSettings.cs index 046668f..19c3e68 100644 --- a/Source/HDRProfile/UserAppSettings.cs +++ b/Source/HDRProfile/UserAppSettings.cs @@ -26,8 +26,8 @@ public class UserAppSettings : BaseViewModel private Guid _defaultProfileGuid = Guid.Empty; private SortableObservableCollection _applicationProfileAssignments; - private ObservableCollection _applicationProfiles; - private ObservableCollection _monitors; + private DispatchingObservableCollection _applicationProfiles; + private DispatchingObservableCollection _monitors; [JsonProperty] @@ -59,18 +59,18 @@ public class UserAppSettings : BaseViewModel public SortableObservableCollection ApplicationProfileAssignments { get => _applicationProfileAssignments; set { _applicationProfileAssignments = value; OnPropertyChanged(); } } [JsonProperty(Order = 1)] - public ObservableCollection ApplicationProfiles { get => _applicationProfiles; set { _applicationProfiles = value; OnPropertyChanged(); } } + public DispatchingObservableCollection ApplicationProfiles { get => _applicationProfiles; set { _applicationProfiles = value; OnPropertyChanged(); } } [JsonProperty] - public ObservableCollection Monitors { get => _monitors; set { _monitors = value; OnPropertyChanged(); } } + public DispatchingObservableCollection Monitors { get => _monitors; set { _monitors = value; OnPropertyChanged(); } } public UserAppSettings() { ApplicationProfileAssignments = new SortableObservableCollection(new ObservableCollection()); - ApplicationProfiles = new ObservableCollection(); - Monitors = new ObservableCollection(); + ApplicationProfiles = new DispatchingObservableCollection(); + Monitors = new DispatchingObservableCollection(); } public static UserAppSettings ReadSettings(string path) diff --git a/Source/HDRProfile/Views/AutoHDRMainView.xaml b/Source/HDRProfile/Views/AutoHDRMainView.xaml index 6d5452e..1a82e61 100644 --- a/Source/HDRProfile/Views/AutoHDRMainView.xaml +++ b/Source/HDRProfile/Views/AutoHDRMainView.xaml @@ -12,8 +12,7 @@ xmlns:root="clr-namespace:AutoHDR" mc:Ignorable="d" Title="AutoHDR" Name="MainWindow" MinHeight="480" MinWidth="480" Closing="Window_Closing" Visibility="{Binding ShowView, Mode=TwoWay, Converter={StaticResource VisibilityBooleanConverter}}" - Height="600" - Width="700" Loaded="MainWindow_Loaded"> + Loaded="MainWindow_Loaded"> diff --git a/Source/HDRProfile/Views/DisplayManagerView.xaml b/Source/HDRProfile/Views/DisplayManagerView.xaml index af967b7..f049174 100644 --- a/Source/HDRProfile/Views/DisplayManagerView.xaml +++ b/Source/HDRProfile/Views/DisplayManagerView.xaml @@ -29,25 +29,36 @@ - + + - + - - + + + + + + + + + - - + - - - + - + + + + + + + - + + + + + + +