Light/Dark themer added for Winform title bar

This commit is contained in:
Usman Shafiq
2022-03-23 19:21:34 -04:00
parent dbfa7478b7
commit c9bd9cd9d3
5 changed files with 103 additions and 3 deletions

View File

@@ -13,7 +13,7 @@ using CefSharp.WinForms;
namespace VRCX
{
public partial class MainForm : Form
public partial class MainForm : WinformBase
{
public static MainForm Instance;
public ChromiumWebBrowser Browser;

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@@ -119,6 +119,10 @@
<Compile Include="VRCXStorage.cs" />
<Compile Include="JsonSerializer.cs" />
<Compile Include="WinApi.cs" />
<Compile Include="WinformBase.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="WinformThemer.cs" />
<EmbeddedResource Include="VRForm.resx">
<DependentUpon>VRForm.cs</DependentUpon>
</EmbeddedResource>

View File

@@ -10,7 +10,7 @@ using CefSharp.WinForms;
namespace VRCX
{
public partial class VRForm : Form
public partial class VRForm : WinformBase
{
public static VRForm Instance;
private ChromiumWebBrowser _browser1;

19
WinformBase.cs Normal file
View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace VRCX
{
public class WinformBase : Form
{
protected override void OnHandleCreated(EventArgs e)
{
WinformThemer.SetThemeToGlobal(this);
base.OnHandleCreated(e);
}
}
}

77
WinformThemer.cs Normal file
View File

@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace VRCX
{
//Based off DWMWA_USE_IMMERSIVE_DARK_MODE, documentation: https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
//dwAttribute was 19 before Windows 20H1, 20 after Windows 20H1
internal static class WinformThemer
{
[DllImport("DwmApi")]
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, int[] pvAttribute, int cbAttribute);
[DllImport("DwmApi")]
private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, IntPtr pvAttribute, int cbAttribute);
private static int currentTheme = 0;
/// <summary>
/// Sets the global theme of the app
/// Light = 0
/// Dark = 1
/// </summary>
public static void SetGlobalTheme(int theme)
{
currentTheme = theme;
foreach (Form form in Application.OpenForms)
{
SetThemeToGlobal(form);
}
}
/// <summary>
/// Gets the global theme of the app
/// Light = 0
/// Dark = 1
/// </summary>
public static int GetGlobalTheme() => currentTheme;
public static void SetThemeToGlobal(Form form)
{
SetThemeToGlobal(form.Handle);
}
private static void SetThemeToGlobal(IntPtr handle)
{
if (GetTheme(handle) != currentTheme)
{
if (DwmSetWindowAttribute(handle, 19, new[] { currentTheme }, 4) != 0)
DwmSetWindowAttribute(handle, 20, new[] { currentTheme }, 4);
}
}
private static int GetTheme(IntPtr handle)
{
//Allocate needed memory
IntPtr curThemePtr = Marshal.AllocHGlobal(4);
//See what window state it currently is
if (DwmGetWindowAttribute(handle, 19, curThemePtr, 4) != 0)
DwmGetWindowAttribute(handle, 20, curThemePtr, 4);
//Read current theme (light = 0, dark = 1)
int theme = Marshal.ReadInt32(curThemePtr);
//Free previously allocated
Marshal.FreeHGlobal(curThemePtr);
return theme;
}
}
}