diff --git a/MainForm.cs b/MainForm.cs index 595e701b..19b1a47c 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -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; diff --git a/VRCX.csproj b/VRCX.csproj index a9af5232..5cde8085 100644 --- a/VRCX.csproj +++ b/VRCX.csproj @@ -1,4 +1,4 @@ - + @@ -119,6 +119,10 @@ + + Form + + VRForm.cs diff --git a/VRForm.cs b/VRForm.cs index a8fbda98..9e543640 100644 --- a/VRForm.cs +++ b/VRForm.cs @@ -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; diff --git a/WinformBase.cs b/WinformBase.cs new file mode 100644 index 00000000..4865e5b1 --- /dev/null +++ b/WinformBase.cs @@ -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); + } + } +} diff --git a/WinformThemer.cs b/WinformThemer.cs new file mode 100644 index 00000000..c89078d3 --- /dev/null +++ b/WinformThemer.cs @@ -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; + + /// + /// Sets the global theme of the app + /// Light = 0 + /// Dark = 1 + /// + public static void SetGlobalTheme(int theme) + { + currentTheme = theme; + foreach (Form form in Application.OpenForms) + { + SetThemeToGlobal(form); + } + } + + /// + /// Gets the global theme of the app + /// Light = 0 + /// Dark = 1 + /// + 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; + } + } +}