diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index 6f3c52063df44..3d6c8e6d53bb9 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -293,3 +293,4 @@ Diagnostic id values for experimental APIs must not be recycled, as that could s | Diagnostic ID | Introduced | Removed | Description | | :---------------- | ---------: | ------: | :---------- | | __`SYSLIB5001`__ | .NET 9 | TBD | `Tensor` and related APIs in System.Numerics.Tensors are experimental in .NET 9 | +| __`SYSLIB5002`__ | .NET 9 | TBD | `SystemColors` alternate colors are experimental in .NET 9 | diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.HIGHCONTRASTW.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.HIGHCONTRASTW.cs new file mode 100644 index 0000000000000..25c9691d325e1 --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.HIGHCONTRASTW.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class User32 + { + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public unsafe partial struct HIGHCONTRASTW + { + internal uint cbSize; + internal HIGHCONTRASTW_FLAGS dwFlags; + internal void* lpszDefaultScheme; + } + + [Flags] + public enum HIGHCONTRASTW_FLAGS : uint + { + HCF_HIGHCONTRASTON = 0x00000001, + HCF_AVAILABLE = 0x00000002, + HCF_HOTKEYACTIVE = 0x00000004, + HCF_CONFIRMHOTKEY = 0x00000008, + HCF_HOTKEYSOUND = 0x00000010, + HCF_INDICATOR = 0x00000020, + HCF_HOTKEYAVAILABLE = 0x00000040, + HCF_OPTION_NOTHEMECHANGE = 0x00001000 + } + } +} diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.SystemParametersInfo.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.SystemParametersInfo.cs index 5bca617b9b6f9..7d4fc2856cffc 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.SystemParametersInfo.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.SystemParametersInfo.cs @@ -11,7 +11,8 @@ internal static partial class User32 public enum SystemParametersAction : uint { SPI_GETICONTITLELOGFONT = 0x1F, - SPI_GETNONCLIENTMETRICS = 0x29 + SPI_GETNONCLIENTMETRICS = 0x29, + SPI_GETHIGHCONTRAST = 0x42 } [LibraryImport(Libraries.User32)] diff --git a/src/libraries/Common/src/System/Experimentals.cs b/src/libraries/Common/src/System/Experimentals.cs index befcdca48327d..39ef81d8462a2 100644 --- a/src/libraries/Common/src/System/Experimentals.cs +++ b/src/libraries/Common/src/System/Experimentals.cs @@ -19,6 +19,9 @@ internal static class Experimentals // Tensor and related APIs are marked as [Experimental] in .NET 9 internal const string TensorTDiagId = "SYSLIB5001"; + // SystemColors alternate colors are marked as [Experimental] in .NET 9 + internal const string SystemColorsDiagId = "SYSLIB5002"; + // When adding a new diagnostic ID, add it to the table in docs\project\list-of-diagnostics.md as well. // Keep new const identifiers above this comment. } diff --git a/src/libraries/System.Drawing.Primitives/System.Drawing.Primitives.sln b/src/libraries/System.Drawing.Primitives/System.Drawing.Primitives.sln index d6a4e28428dd1..3e45053326007 100644 --- a/src/libraries/System.Drawing.Primitives/System.Drawing.Primitives.sln +++ b/src/libraries/System.Drawing.Primitives/System.Drawing.Primitives.sln @@ -1,4 +1,8 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35111.106 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{39205290-06C5-468E-B5C9-D9C5737909EE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Collections.NonGeneric", "..\System.Collections.NonGeneric\ref\System.Collections.NonGeneric.csproj", "{4B06D595-C5B5-49E3-BC5D-7CA55B52D91B}" @@ -45,11 +49,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{722DCDC1-751 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{8349AD04-5979-4347-A869-7F76B043453E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "tools\gen", "{1ACFEEFC-7E61-483E-9CAF-1EB2DFC11558}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{1ACFEEFC-7E61-483E-9CAF-1EB2DFC11558}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "tools\src", "{D99A011B-F48D-4E22-9C5B-050294758522}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D99A011B-F48D-4E22-9C5B-050294758522}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "tools\ref", "{5CB40A8A-59D5-4E57-8F9A-D716C5BDFDC7}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{5CB40A8A-59D5-4E57-8F9A-D716C5BDFDC7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0205F064-E9AB-408E-BC47-D1EB62C753C7}" EndProject @@ -141,29 +145,33 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {39205290-06C5-468E-B5C9-D9C5737909EE} = {B004DC3D-DA89-4C76-8D15-327CCDB6D7C0} - {515B6C1E-757F-497E-9707-37B5822FFC9A} = {B004DC3D-DA89-4C76-8D15-327CCDB6D7C0} {4B06D595-C5B5-49E3-BC5D-7CA55B52D91B} = {F2D0660B-B4A3-4039-A47D-63F9D1CE19B6} {6ED31F56-EBDB-4E4D-A6D5-8F6078B1A241} = {F2D0660B-B4A3-4039-A47D-63F9D1CE19B6} {9D080C1F-6334-4C14-BABF-D0D9132C0D83} = {F2D0660B-B4A3-4039-A47D-63F9D1CE19B6} {F92BFBC7-A148-44D5-A977-01926068615D} = {F2D0660B-B4A3-4039-A47D-63F9D1CE19B6} {D2E753F4-34A3-4641-9C0F-53539147CCF2} = {F2D0660B-B4A3-4039-A47D-63F9D1CE19B6} + {80A68643-0E37-4525-BF06-F50C3BF7B867} = {722DCDC1-7510-4B50-93F4-51E5FF833B2A} + {515B6C1E-757F-497E-9707-37B5822FFC9A} = {B004DC3D-DA89-4C76-8D15-327CCDB6D7C0} {731DA2F5-004D-46F0-8751-4945163E8DF4} = {F2D0660B-B4A3-4039-A47D-63F9D1CE19B6} {D8C6E8A8-4E73-42CD-A310-C63B64844A4C} = {F2D0660B-B4A3-4039-A47D-63F9D1CE19B6} - {FD462F99-C9F6-4D3E-B080-F5E337E8F2F8} = {F2D0660B-B4A3-4039-A47D-63F9D1CE19B6} - {80A68643-0E37-4525-BF06-F50C3BF7B867} = {722DCDC1-7510-4B50-93F4-51E5FF833B2A} {F06CCE8D-0066-4B17-8EF0-162AE711F6D8} = {8349AD04-5979-4347-A869-7F76B043453E} {315E574D-6A26-4A89-83B5-1C948F3C83D2} = {8349AD04-5979-4347-A869-7F76B043453E} {9ECCC771-064F-403E-8E0E-7B049AAFAD36} = {8349AD04-5979-4347-A869-7F76B043453E} + {FD462F99-C9F6-4D3E-B080-F5E337E8F2F8} = {F2D0660B-B4A3-4039-A47D-63F9D1CE19B6} {D5E974B9-EB58-4D32-A4F4-C31559436DEA} = {1ACFEEFC-7E61-483E-9CAF-1EB2DFC11558} {D2D8DF0A-836A-4521-A9F5-349F91E87046} = {1ACFEEFC-7E61-483E-9CAF-1EB2DFC11558} - {1ACFEEFC-7E61-483E-9CAF-1EB2DFC11558} = {0205F064-E9AB-408E-BC47-D1EB62C753C7} {198C17DB-F65F-4165-996B-128E3123A6CF} = {D99A011B-F48D-4E22-9C5B-050294758522} {A92D7FC7-E3A9-4260-8F25-7FCF3AA900DC} = {D99A011B-F48D-4E22-9C5B-050294758522} - {D99A011B-F48D-4E22-9C5B-050294758522} = {0205F064-E9AB-408E-BC47-D1EB62C753C7} {0A6457CF-5932-44F6-9983-978FA163B3A5} = {5CB40A8A-59D5-4E57-8F9A-D716C5BDFDC7} + {1ACFEEFC-7E61-483E-9CAF-1EB2DFC11558} = {0205F064-E9AB-408E-BC47-D1EB62C753C7} + {D99A011B-F48D-4E22-9C5B-050294758522} = {0205F064-E9AB-408E-BC47-D1EB62C753C7} {5CB40A8A-59D5-4E57-8F9A-D716C5BDFDC7} = {0205F064-E9AB-408E-BC47-D1EB62C753C7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E2DD25F1-FA29-41D5-AB37-65DDC6A49304} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{a92d7fc7-e3a9-4260-8f25-7fcf3aa900dc}*SharedItemsImports = 5 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{d2d8df0a-836a-4521-a9f5-349f91e87046}*SharedItemsImports = 5 + EndGlobalSection EndGlobal diff --git a/src/libraries/System.Drawing.Primitives/ref/System.Drawing.Primitives.cs b/src/libraries/System.Drawing.Primitives/ref/System.Drawing.Primitives.cs index 52f5b2f54bd17..4ab096f9be624 100644 --- a/src/libraries/System.Drawing.Primitives/ref/System.Drawing.Primitives.cs +++ b/src/libraries/System.Drawing.Primitives/ref/System.Drawing.Primitives.cs @@ -625,5 +625,7 @@ public static partial class SystemColors public static System.Drawing.Color Window { get { throw null; } } public static System.Drawing.Color WindowFrame { get { throw null; } } public static System.Drawing.Color WindowText { get { throw null; } } + [System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5002", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + public static bool UseAlternativeColorSet { get { throw null; } set { } } } } diff --git a/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj b/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj index b0db347a20569..58b5852c2c916 100644 --- a/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj +++ b/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj @@ -29,6 +29,7 @@ Link="System\Drawing\ColorConverterCommon.cs" /> + @@ -36,8 +37,12 @@ Link="Common\Interop\Windows\Interop.Libraries.cs" /> + + diff --git a/src/libraries/System.Drawing.Primitives/src/System/Drawing/KnownColorTable.cs b/src/libraries/System.Drawing.Primitives/src/System/Drawing/KnownColorTable.cs index 7ac095098ca37..06922761f4b3e 100644 --- a/src/libraries/System.Drawing.Primitives/src/System/Drawing/KnownColorTable.cs +++ b/src/libraries/System.Drawing.Primitives/src/System/Drawing/KnownColorTable.cs @@ -18,32 +18,32 @@ internal static class KnownColorTable 0, // "System" colors, Part 1 #if FEATURE_WINDOWS_SYSTEM_COLORS - (uint)(byte)Interop.User32.Win32SystemColors.ActiveBorder, - (uint)(byte)Interop.User32.Win32SystemColors.ActiveCaption, - (uint)(byte)Interop.User32.Win32SystemColors.ActiveCaptionText, - (uint)(byte)Interop.User32.Win32SystemColors.AppWorkspace, - (uint)(byte)Interop.User32.Win32SystemColors.Control, - (uint)(byte)Interop.User32.Win32SystemColors.ControlDark, - (uint)(byte)Interop.User32.Win32SystemColors.ControlDarkDark, - (uint)(byte)Interop.User32.Win32SystemColors.ControlLight, - (uint)(byte)Interop.User32.Win32SystemColors.ControlLightLight, - (uint)(byte)Interop.User32.Win32SystemColors.ControlText, - (uint)(byte)Interop.User32.Win32SystemColors.Desktop, - (uint)(byte)Interop.User32.Win32SystemColors.GrayText, - (uint)(byte)Interop.User32.Win32SystemColors.Highlight, - (uint)(byte)Interop.User32.Win32SystemColors.HighlightText, - (uint)(byte)Interop.User32.Win32SystemColors.HotTrack, - (uint)(byte)Interop.User32.Win32SystemColors.InactiveBorder, - (uint)(byte)Interop.User32.Win32SystemColors.InactiveCaption, - (uint)(byte)Interop.User32.Win32SystemColors.InactiveCaptionText, - (uint)(byte)Interop.User32.Win32SystemColors.Info, - (uint)(byte)Interop.User32.Win32SystemColors.InfoText, - (uint)(byte)Interop.User32.Win32SystemColors.Menu, - (uint)(byte)Interop.User32.Win32SystemColors.MenuText, - (uint)(byte)Interop.User32.Win32SystemColors.ScrollBar, - (uint)(byte)Interop.User32.Win32SystemColors.Window, - (uint)(byte)Interop.User32.Win32SystemColors.WindowFrame, - (uint)(byte)Interop.User32.Win32SystemColors.WindowText, + (byte)Interop.User32.Win32SystemColors.ActiveBorder, + (byte)Interop.User32.Win32SystemColors.ActiveCaption, + (byte)Interop.User32.Win32SystemColors.ActiveCaptionText, + (byte)Interop.User32.Win32SystemColors.AppWorkspace, + (byte)Interop.User32.Win32SystemColors.Control, + (byte)Interop.User32.Win32SystemColors.ControlDark, + (byte)Interop.User32.Win32SystemColors.ControlDarkDark, + (byte)Interop.User32.Win32SystemColors.ControlLight, + (byte)Interop.User32.Win32SystemColors.ControlLightLight, + (byte)Interop.User32.Win32SystemColors.ControlText, + (byte)Interop.User32.Win32SystemColors.Desktop, + (byte)Interop.User32.Win32SystemColors.GrayText, + (byte)Interop.User32.Win32SystemColors.Highlight, + (byte)Interop.User32.Win32SystemColors.HighlightText, + (byte)Interop.User32.Win32SystemColors.HotTrack, + (byte)Interop.User32.Win32SystemColors.InactiveBorder, + (byte)Interop.User32.Win32SystemColors.InactiveCaption, + (byte)Interop.User32.Win32SystemColors.InactiveCaptionText, + (byte)Interop.User32.Win32SystemColors.Info, + (byte)Interop.User32.Win32SystemColors.InfoText, + (byte)Interop.User32.Win32SystemColors.Menu, + (byte)Interop.User32.Win32SystemColors.MenuText, + (byte)Interop.User32.Win32SystemColors.ScrollBar, + (byte)Interop.User32.Win32SystemColors.Window, + (byte)Interop.User32.Win32SystemColors.WindowFrame, + (byte)Interop.User32.Win32SystemColors.WindowText, #else // Hard-coded constants, based on default Windows settings. 0xFFD4D0C8, // ActiveBorder @@ -217,13 +217,13 @@ internal static class KnownColorTable 0xFF9ACD32, // YellowGreen #if FEATURE_WINDOWS_SYSTEM_COLORS // "System" colors, Part 2 - (uint)(byte)Interop.User32.Win32SystemColors.ButtonFace, - (uint)(byte)Interop.User32.Win32SystemColors.ButtonHighlight, - (uint)(byte)Interop.User32.Win32SystemColors.ButtonShadow, - (uint)(byte)Interop.User32.Win32SystemColors.GradientActiveCaption, - (uint)(byte)Interop.User32.Win32SystemColors.GradientInactiveCaption, - (uint)(byte)Interop.User32.Win32SystemColors.MenuBar, - (uint)(byte)Interop.User32.Win32SystemColors.MenuHighlight, + (byte)Interop.User32.Win32SystemColors.ButtonFace, + (byte)Interop.User32.Win32SystemColors.ButtonHighlight, + (byte)Interop.User32.Win32SystemColors.ButtonShadow, + (byte)Interop.User32.Win32SystemColors.GradientActiveCaption, + (byte)Interop.User32.Win32SystemColors.GradientInactiveCaption, + (byte)Interop.User32.Win32SystemColors.MenuBar, + (byte)Interop.User32.Win32SystemColors.MenuHighlight, #else 0xFFF0F0F0, // ButtonFace 0xFFFFFFFF, // ButtonHighlight @@ -242,36 +242,8 @@ internal static class KnownColorTable [ // "not a known color" KnownColorKindUnknown, + // "System" colors, Part 1 -#if FEATURE_WINDOWS_SYSTEM_COLORS - KnownColorKindSystem, // ActiveBorder - KnownColorKindSystem, // ActiveCaption - KnownColorKindSystem, // ActiveCaptionText - KnownColorKindSystem, // AppWorkspace - KnownColorKindSystem, // Control - KnownColorKindSystem, // ControlDark - KnownColorKindSystem, // ControlDarkDark - KnownColorKindSystem, // ControlLight - KnownColorKindSystem, // ControlLightLight - KnownColorKindSystem, // ControlText - KnownColorKindSystem, // Desktop - KnownColorKindSystem, // GrayText - KnownColorKindSystem, // Highlight - KnownColorKindSystem, // HighlightText - KnownColorKindSystem, // HotTrack - KnownColorKindSystem, // InactiveBorder - KnownColorKindSystem, // InactiveCaption - KnownColorKindSystem, // InactiveCaptionText - KnownColorKindSystem, // Info - KnownColorKindSystem, // InfoText - KnownColorKindSystem, // Menu - KnownColorKindSystem, // MenuText - KnownColorKindSystem, // ScrollBar - KnownColorKindSystem, // Window - KnownColorKindSystem, // WindowFrame - KnownColorKindSystem, // WindowText -#else - // Hard-coded constants, based on default Windows settings. KnownColorKindSystem, // ActiveBorder KnownColorKindSystem, // ActiveCaption KnownColorKindSystem, // ActiveCaptionText @@ -298,7 +270,7 @@ internal static class KnownColorTable KnownColorKindSystem, // Window KnownColorKindSystem, // WindowFrame KnownColorKindSystem, // WindowText -#endif + // "Web" Colors, Part 1 KnownColorKindWeb, // Transparent KnownColorKindWeb, // AliceBlue @@ -441,16 +413,8 @@ internal static class KnownColorTable KnownColorKindWeb, // WhiteSmoke KnownColorKindWeb, // Yellow KnownColorKindWeb, // YellowGreen -#if FEATURE_WINDOWS_SYSTEM_COLORS - // "System" colors, Part 2 - KnownColorKindSystem, // ButtonFace - KnownColorKindSystem, // ButtonHighlight - KnownColorKindSystem, // ButtonShadow - KnownColorKindSystem, // GradientActiveCaption - KnownColorKindSystem, // GradientInactiveCaption - KnownColorKindSystem, // MenuBar - KnownColorKindSystem, // MenuHighlight -#else + + // "System" colors, Part 1 KnownColorKindSystem, // ButtonFace KnownColorKindSystem, // ButtonHighlight KnownColorKindSystem, // ButtonShadow @@ -458,11 +422,56 @@ internal static class KnownColorTable KnownColorKindSystem, // GradientInactiveCaption KnownColorKindSystem, // MenuBar KnownColorKindSystem, // MenuHighlight -#endif + // "Web" colors, Part 2 KnownColorKindWeb, // RebeccaPurple ]; + // These values were based on manual investigation of dark mode themes in the + // Win32 Common Controls and WinUI. There aren't direct mappings published by + // Windows, these may change slightly when this feature is finalized to make + // sure we have the best experience in hybrid dark mode scenarios (mixing + // WPF, WinForms, and WinUI). + private static ReadOnlySpan AlternateSystemColors => + [ + 0, // To align with KnownColor.ActiveBorder = 1 + + // Existing New + 0xFF464646, // FFB4B4B4 - FF464646: ActiveBorder - Dark gray + 0xFF3C5F78, // FF99B4D1 - FF3C5F78: ActiveCaption - Highlighted Text Background + 0xFFFFFFFF, // FF000000 - FFBEBEBE: ActiveCaptionText - White + 0xFF3C3C3C, // FFABABAB - FF3C3C3C: AppWorkspace - Panel Background + 0xFF202020, // FFF0F0F0 - FF373737: Control - Normal Panel/Windows Background + 0xFF4A4A4A, // FFA0A0A0 - FF464646: ControlDark - A lighter gray for dark mode + 0xFF5A5A5A, // FF696969 - FF5A5A5A: ControlDarkDark - An even lighter gray for dark mode + 0xFF2E2E2E, // FFE3E3E3 - FF2E2E2E: ControlLight - Unfocused Textbox Background + 0xFF1F1F1F, // FFFFFFFF - FF1F1F1F: ControlLightLight - Focused Textbox Background + 0xFFFFFFFF, // FF000000 - FFFFFFFF: ControlText - Control Forecolor and Text Color + 0xFF101010, // FF000000 - FF101010: Desktop - Black + 0xFF969696, // FF6D6D6D - FF969696: GrayText - Prompt Text Focused TextBox + 0xFF2864B4, // FF0078D7 - FF2864B4: Highlight - Highlighted Panel in DarkMode + 0xFF000000, // FFFFFFFF - FF000000: HighlightText - White + 0xFF2D5FAF, // FF0066CC - FF2D5FAF: HotTrack - Background of the ToggleSwitch + 0xFF3C3F41, // FFF4F7FC - FF3C3F41: InactiveBorder - Dark gray + 0xFF374B5A, // FFBFCBDD - FF374B5A: InactiveCaption - Highlighted Panel in DarkMode + 0xFFBEBEBE, // FF000000 - FFBEBEBE: InactiveCaptionText - Middle Dark Panel + 0xFF50503C, // FFFFFFE1 - FF50503C: Info - Link Label + 0xFFBEBEBE, // FF000000 - FFBEBEBE: InfoText - Prompt Text Color + 0xFF373737, // FFF0F0F0 - FF373737: Menu - Normal Menu Background + 0xFFF0F0F0, // FF000000 - FFF0F0F0: MenuText - White + 0xFF505050, // FFC8C8C8 - FF505050: ScrollBar - Scrollbars and Scrollbar Arrows + 0xFF323232, // FFFFFFFF - FF323232: Window - Window Background + 0xFF282828, // FF646464 - FF282828: WindowFrame - White + 0xFFF0F0F0, // FF000000 - FFF0F0F0: WindowText - White + 0xFF202020, // FFF0F0F0 - FF373737: ButtonFace - Same as Window Background + 0xFF101010, // FFFFFFFF - FF101010: ButtonHighlight - White + 0xFF464646, // FFA0A0A0 - FF464646: ButtonShadow - Same as Scrollbar Elements + 0XFF416482, // FFB9D1EA - FF416482: GradientActiveCaption - Same as Highlighted Text Background + 0xFF557396, // FFD7E4F2 - FF557396: GradientInactiveCaption - Same as Highlighted Panel in DarkMode + 0xFF373737, // FFF0F0F0 - FF373737: MenuBar - Same as Normal Menu Background + 0xFF2A80D2 // FF3399FF - FF2A80D2: MenuHighlight - Same as Highlighted Menu Background + ]; + internal static Color ArgbToKnownColor(uint argb) { Debug.Assert((argb & Color.ARGBAlphaMask) == Color.ARGBAlphaMask); @@ -490,19 +499,50 @@ public static uint KnownColorToArgb(KnownColor color) : ColorValueTable[(int)color]; } + private static uint GetAlternateSystemColorArgb(KnownColor color) + { + // Shift the original (split) index to fit the alternate color map. + int index = color <= KnownColor.WindowText + ? (int)color + : (int)color - (int)KnownColor.ButtonFace + (int)KnownColor.WindowText + 1; + + return AlternateSystemColors[index]; + } + #if FEATURE_WINDOWS_SYSTEM_COLORS public static uint GetSystemColorArgb(KnownColor color) { Debug.Assert(Color.IsKnownColorSystem(color)); - return ColorTranslator.COLORREFToARGB(Interop.User32.GetSysColor((byte)ColorValueTable[(int)color])); + return !SystemColors.s_useAlternativeColorSet || HighContrastEnabled() + ? ColorTranslator.COLORREFToARGB(Interop.User32.GetSysColor((byte)ColorValueTable[(int)color])) + : GetAlternateSystemColorArgb(color); + } + + private static unsafe bool HighContrastEnabled() + { + Interop.User32.HIGHCONTRASTW highContrast = default; + + // Note that the documentation for HIGHCONTRASTW says that the lpszDefaultScheme member needs to be + // freed, but this is incorrect. No internal users ever free the pointer and the pointer never changes. + highContrast.cbSize = (uint)sizeof(Interop.User32.HIGHCONTRASTW); + bool success = Interop.User32.SystemParametersInfoW( + Interop.User32.SystemParametersAction.SPI_GETHIGHCONTRAST, + highContrast.cbSize, + &highContrast, + 0); // This has no meaning when getting values + + return success && highContrast.dwFlags.HasFlag(Interop.User32.HIGHCONTRASTW_FLAGS.HCF_HIGHCONTRASTON); } #else + public static uint GetSystemColorArgb(KnownColor color) { Debug.Assert(Color.IsKnownColorSystem(color)); - return ColorValueTable[(int)color]; + return (!SystemColors.s_useAlternativeColorSet) + ? ColorValueTable[(int)color] + : GetAlternateSystemColorArgb(color); } #endif } diff --git a/src/libraries/System.Drawing.Primitives/src/System/Drawing/SystemColors.cs b/src/libraries/System.Drawing.Primitives/src/System/Drawing/SystemColors.cs index 3549c80735937..daf6e33770ce9 100644 --- a/src/libraries/System.Drawing.Primitives/src/System/Drawing/SystemColors.cs +++ b/src/libraries/System.Drawing.Primitives/src/System/Drawing/SystemColors.cs @@ -1,10 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace System.Drawing { public static class SystemColors { + internal static bool s_useAlternativeColorSet; + public static Color ActiveBorder => Color.FromKnownColor(KnownColor.ActiveBorder); public static Color ActiveCaption => Color.FromKnownColor(KnownColor.ActiveCaption); public static Color ActiveCaptionText => Color.FromKnownColor(KnownColor.ActiveCaptionText); @@ -47,5 +51,29 @@ public static class SystemColors public static Color Window => Color.FromKnownColor(KnownColor.Window); public static Color WindowFrame => Color.FromKnownColor(KnownColor.WindowFrame); public static Color WindowText => Color.FromKnownColor(KnownColor.WindowText); + + /// + /// When , system values will return + /// the alternative color set (as returned by statics or + /// ). This is currently "dark mode" + /// variants of the system colors. + /// + /// + /// + /// values are always looked up every + /// time you use them and do not retain any other context. As such, existing + /// values will change when this property is set. + /// + /// + /// On Windows, system values will always return the current + /// Windows color when the OS has a high contrast theme enabled. + /// + /// + [Experimental(Experimentals.SystemColorsDiagId, UrlFormat = Experimentals.SharedUrlFormat)] + public static bool UseAlternativeColorSet + { + get => s_useAlternativeColorSet; + set => s_useAlternativeColorSet = value; + } } } diff --git a/src/libraries/System.Drawing.Primitives/tests/ColorTests.cs b/src/libraries/System.Drawing.Primitives/tests/ColorTests.cs index c1267aac24008..a4a674d9b517b 100644 --- a/src/libraries/System.Drawing.Primitives/tests/ColorTests.cs +++ b/src/libraries/System.Drawing.Primitives/tests/ColorTests.cs @@ -448,7 +448,7 @@ public void GetSaturation(int r, int g, int b, float expected) public static IEnumerable Equality_MemberData() { yield return new object[] { Color.AliceBlue, Color.AliceBlue, true }; - yield return new object[] { Color.AliceBlue, Color.White, false}; + yield return new object[] { Color.AliceBlue, Color.White, false }; yield return new object[] { Color.AliceBlue, Color.Black, false }; yield return new object[] { Color.FromArgb(255, 1, 2, 3), Color.FromArgb(255, 1, 2, 3), true }; @@ -466,7 +466,7 @@ public static IEnumerable Equality_MemberData() string someNameConstructed = string.Join("", "Some", "Name"); Assert.NotSame("SomeName", someNameConstructed); // If this fails the above must be changed so this test is correct. - yield return new object[] {Color.FromName("SomeName"), Color.FromName(someNameConstructed), true}; + yield return new object[] { Color.FromName("SomeName"), Color.FromName(someNameConstructed), true }; } [Theory] @@ -889,5 +889,27 @@ private static int GetColorRefValue(Color color) // The COLORREF value has the following hexadecimal form: 0x00bbggrr. return color.B << 16 | color.G << 8 | color.R; } + + [Fact] + public void SystemColor_AlternativeColors() + { + try + { +#pragma warning disable SYSLIB5002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Drawing.SystemColors.UseAlternativeColorSet = true; +#pragma warning restore SYSLIB5002 + + Assert.Equal(0xFF464646, (uint)Drawing.SystemColors.ActiveBorder.ToArgb()); + Assert.Equal(0xFFF0F0F0, (uint)Drawing.SystemColors.WindowText.ToArgb()); + Assert.Equal(0xFF202020, (uint)Drawing.SystemColors.ButtonFace.ToArgb()); + Assert.Equal(0xFF2A80D2, (uint)Drawing.SystemColors.MenuHighlight.ToArgb()); + } + finally + { +#pragma warning disable SYSLIB5002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Drawing.SystemColors.UseAlternativeColorSet = false; +#pragma warning restore SYSLIB5002 + } + } } }