Add dark theme titlebar

This commit is contained in:
Charles Milette 2019-05-22 13:04:53 -04:00
parent a821269e9e
commit 71bfdd8ba4
No known key found for this signature in database
GPG key ID: 1A5AE81377AD973A
7 changed files with 135 additions and 48 deletions

View file

@ -24,6 +24,7 @@
#endregion License Information (GPL v3)
using System;
using System.Windows.Forms;
namespace ShareX.HelpersLib
{
@ -69,5 +70,23 @@ public void Dispose()
autoEnable = false;
}
}
public static bool EnableDarkTitlebar(Form form, bool enabled)
{
if (Helpers.IsWindows10OrGreater() && Helpers.IsWindowsBuildOrGreater(17763))
{
try
{
NativeMethods.SetWindowAttribute(form.Handle, WindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE, enabled);
return true;
}
catch (Exception e)
{
DebugHelper.WriteException(e);
}
}
return false;
}
}
}

View file

@ -624,6 +624,11 @@ public static bool IsWindows10OrGreater()
return OSVersion.Major >= 10;
}
public static bool IsWindowsBuildOrGreater(int buildId)
{
return OSVersion.Build >= buildId;
}
public static bool IsDefaultInstallDir()
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);

View file

@ -192,27 +192,6 @@ public enum DWM_BB
TransitionMaximized = 4
}
[Flags]
public enum DwmWindowAttribute
{
NCRenderingEnabled = 1,
NCRenderingPolicy,
TransitionsForceDisabled,
AllowNCPaint,
CaptionButtonBounds,
NonClientRtlLayout,
ForceIconicRepresentation,
Flip3DPolicy,
ExtendedFrameBounds,
HasIconicBitmap,
DisallowPeek,
ExcludedFromPeek,
Cloak,
Cloaked,
FreezeRepresentation,
Last
}
[Flags]
public enum DwmNCRenderingPolicy
{
@ -2038,6 +2017,76 @@ public enum CompositionAction : uint
DWM_EC_ENABLECOMPOSITION = 1
}
public enum WindowAttribute : uint
{
/// <summary>
/// Use with DwmGetWindowAttribute. Discovers whether non-client rendering is enabled. The retrieved value is of type BOOL. TRUE if non-client rendering is enabled; otherwise, FALSE.
/// </summary>
DWMWA_NCRENDERING_ENABLED = 1,
/// <summary>
/// Use with DwmSetWindowAttribute. Sets the non-client rendering policy. The pvAttribute parameter points to a value from the DWMNCRENDERINGPOLICY enumeration.
/// </summary>
DWMWA_NCRENDERING_POLICY,
/// <summary>
/// Use with DwmSetWindowAttribute. Enables or forcibly disables DWM transitions. The pvAttribute parameter points to a value of TRUE to disable transitions or FALSE to enable transitions.
/// </summary>
DWMWA_TRANSITIONS_FORCEDISABLED,
/// <summary>
/// Use with DwmSetWindowAttribute. Enables content rendered in the non-client area to be visible on the frame drawn by DWM. The pvAttribute parameter points to a value of TRUE to enable content rendered in the non-client area to be visible on the frame; otherwise, it points to FALSE.
/// </summary>
DWMWA_ALLOW_NCPAINT,
/// <summary>
/// Use with DwmGetWindowAttribute. Retrieves the bounds of the caption button area in the window-relative space. The retrieved value is of type RECT.
/// </summary>
DWMWA_CAPTION_BUTTON_BOUNDS,
/// <summary>
/// Use with DwmSetWindowAttribute. Specifies whether non-client content is right-to-left (RTL) mirrored. The pvAttribute parameter points to a value of TRUE if the non-client content is right-to-left (RTL) mirrored; otherwise, it points to FALSE.
/// </summary>
DWMWA_NONCLIENT_RTL_LAYOUT,
/// <summary>
/// Use with DwmSetWindowAttribute. Forces the window to display an iconic thumbnail or peek representation (a static bitmap), even if a live or snapshot representation of the window is available. This value normally is set during a window's creation and not changed throughout the window's lifetime. Some scenarios, however, might require the value to change over time. The pvAttribute parameter points to a value of TRUE to require a iconic thumbnail or peek representation; otherwise, it points to FALSE.
/// </summary>
DWMWA_FORCE_ICONIC_REPRESENTATION,
/// <summary>
/// Use with DwmSetWindowAttribute. Sets how Flip3D treats the window. The pvAttribute parameter points to a value from the DWMFLIP3DWINDOWPOLICY enumeration.
/// </summary>
DWMWA_FLIP3D_POLICY,
/// <summary>
/// Use with DwmGetWindowAttribute. Retrieves the extended frame bounds rectangle in screen space. The retrieved value is of type RECT.
/// </summary>
DWMWA_EXTENDED_FRAME_BOUNDS,
/// <summary>
/// Use with DwmSetWindowAttribute. The window will provide a bitmap for use by DWM as an iconic thumbnail or peek representation (a static bitmap) for the window. DWMWA_HAS_ICONIC_BITMAP can be specified with DWMWA_FORCE_ICONIC_REPRESENTATION. DWMWA_HAS_ICONIC_BITMAP normally is set during a window's creation and not changed throughout the window's lifetime. Some scenarios, however, might require the value to change over time. The pvAttribute parameter points to a value of TRUE to inform DWM that the window will provide an iconic thumbnail or peek representation; otherwise, it points to FALSE.
/// </summary>
DWMWA_HAS_ICONIC_BITMAP,
/// <summary>
/// Use with DwmSetWindowAttribute. Do not show peek preview for the window. The peek view shows a full-sized preview of the window when the mouse hovers over the window's thumbnail in the taskbar. If this attribute is set, hovering the mouse pointer over the window's thumbnail dismisses peek (in case another window in the group has a peek preview showing). The pvAttribute parameter points to a value of TRUE to prevent peek functionality or FALSE to allow it.
/// </summary>
DWMWA_DISALLOW_PEEK,
/// <summary>
/// Use with DwmSetWindowAttribute. Prevents a window from fading to a glass sheet when peek is invoked. The pvAttribute parameter points to a value of TRUE to prevent the window from fading during another window's peek or FALSE for normal behavior.
/// </summary>
DWMWA_EXCLUDED_FROM_PEEK,
/// <summary>
/// Use with DwmSetWindowAttribute. Cloaks the window such that it is not visible to the user. The window is still composed by DWM.
/// </summary>
DWMWA_CLOAK,
/// <summary>
/// Use with DwmGetWindowAttribute.
/// </summary>
DWMWA_CLOAKED,
/// <summary>
/// Use with DwmSetWindowAttribute. Freeze the window's thumbnail image with its current visuals. Do no further live updates on the thumbnail image to match the window's contents.
/// </summary>
DWMWA_FREEZE_REPRESENTATION,
/// <summary>
/// The maximum recognized DWMWINDOWATTRIBUTE value, used for validation purposes.
/// </summary>
DWMWA_LAST,
// Undocumented, available since October 2018 update (build 17763)
DWMWA_USE_IMMERSIVE_DARK_MODE = 19
}
public enum InputType : int
{
InputMouse,

View file

@ -405,13 +405,7 @@ public static partial class NativeMethods
#region dwmapi.dll
[DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out RECT pvAttribute, int cbAttribute);
[DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out bool pvAttribute, int cbAttribute);
[DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out int pvAttribute, int cbAttribute);
public static extern int DwmGetWindowAttribute(IntPtr hwnd, WindowAttribute dwAttribute, IntPtr pvAttribute, int cbAttribute);
[DllImport("dwmapi.dll")]
public static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind);
@ -425,8 +419,8 @@ public static partial class NativeMethods
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern bool DwmIsCompositionEnabled();
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmSetWindowAttribute(IntPtr hwnd, WindowAttribute attr, IntPtr attrValue, int attrSize);
[DllImport("dwmapi.dll")]
public static extern int DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size);

View file

@ -212,23 +212,44 @@ public static bool IsDWMEnabled()
public static bool GetExtendedFrameBounds(IntPtr handle, out Rectangle rectangle)
{
RECT rect;
int result = DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.ExtendedFrameBounds, out rect, Marshal.SizeOf(typeof(RECT)));
bool result = GetWindowAttribute(handle, WindowAttribute.DWMWA_EXTENDED_FRAME_BOUNDS, out RECT rect);
rectangle = rect;
return result == 0;
return result;
}
public static bool GetNCRenderingEnabled(IntPtr handle)
public static bool GetNCRenderingEnabled(IntPtr handle) => GetWindowAttribute(handle, WindowAttribute.DWMWA_NCRENDERING_ENABLED, out bool enabled) && enabled;
public static void SetNCRenderingPolicy(IntPtr handle, DwmNCRenderingPolicy renderingPolicy) => SetWindowAttribute(handle, WindowAttribute.DWMWA_NCRENDERING_POLICY, renderingPolicy);
public static bool GetWindowAttribute<T>(IntPtr handle, WindowAttribute attribute, out T value) where T : unmanaged
{
bool enabled;
int result = DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.NCRenderingEnabled, out enabled, sizeof(bool));
return result == 0 && enabled;
int size = Marshal.SizeOf<T>();
IntPtr temp = Marshal.AllocHGlobal(size);
try
{
int result = DwmGetWindowAttribute(handle, attribute, temp, size);
value = Marshal.PtrToStructure<T>(temp);
return result == 0;
}
finally
{
Marshal.FreeHGlobal(temp);
}
}
public static void SetNCRenderingPolicy(IntPtr handle, DwmNCRenderingPolicy renderingPolicy)
public static void SetWindowAttribute<T>(IntPtr handle, WindowAttribute attribute, T value) where T : unmanaged
{
int renderPolicy = (int)renderingPolicy;
DwmSetWindowAttribute(handle, (int)DwmWindowAttribute.NCRenderingPolicy, ref renderPolicy, sizeof(int));
int size = Marshal.SizeOf<T>();
IntPtr temp = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(value, temp, false);
DwmSetWindowAttribute(handle, attribute, temp, size);
}
finally
{
Marshal.FreeHGlobal(temp);
}
}
public static Rectangle GetWindowRect(IntPtr handle)
@ -347,9 +368,7 @@ public static bool IsWindowCloaked(IntPtr handle)
{
if (IsDWMEnabled())
{
int cloaked;
int result = DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.Cloaked, out cloaked, sizeof(int));
return result == 0 && cloaked != 0;
return GetWindowAttribute(handle, WindowAttribute.DWMWA_CLOAKED, out bool cloaked) && cloaked;
}
return false;

View file

@ -33,7 +33,7 @@
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>7.2</LangVersion>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -49,7 +49,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<DebugSymbols>false</DebugSymbols>
<LangVersion>7.2</LangVersion>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Steam|AnyCPU'">
<OutputPath>bin\Steam\</OutputPath>
@ -61,7 +61,7 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>7.2</LangVersion>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'WindowsStore|AnyCPU'">
<OutputPath>bin\WindowsStore\</OutputPath>
@ -73,7 +73,7 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>7.2</LangVersion>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'WindowsStoreDebug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
@ -86,7 +86,7 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>7.2</LangVersion>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />

View file

@ -761,6 +761,7 @@ private void UpdateTaskViewMode()
private void UpdateTheme()
{
DWMManager.EnableDarkTitlebar(this, ShareXResources.UseDarkTheme);
if (ShareXResources.UseDarkTheme)
{
tsMain.Renderer = new ToolStripDarkRenderer();