From c9bd9cd9d3f5aa0c12ff7dcf9eb8cd2af25b67df Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Wed, 23 Mar 2022 19:21:34 -0400 Subject: [PATCH 01/11] Light/Dark themer added for Winform title bar --- MainForm.cs | 2 +- VRCX.csproj | 6 +++- VRForm.cs | 2 +- WinformBase.cs | 19 ++++++++++++ WinformThemer.cs | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 WinformBase.cs create mode 100644 WinformThemer.cs 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; + } + } +} From 8b66fd58250d2d64848be6c821c4ff216831b171 Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Wed, 23 Mar 2022 22:12:35 -0400 Subject: [PATCH 02/11] Moved PInvoke stuff to seperate class, Added jank force refresh of window on theme change --- InvisPopup.Designer.cs | 46 ++++++++++++++++ InvisPopup.cs | 26 +++++++++ InvisPopup.resx | 120 +++++++++++++++++++++++++++++++++++++++++ MainForm.Designer.cs | 42 ++++++++++++--- MainForm.cs | 10 ++++ VRCX.csproj | 9 ++++ WinformThemer.cs | 68 +++++++++++++++++++---- 7 files changed, 303 insertions(+), 18 deletions(-) create mode 100644 InvisPopup.Designer.cs create mode 100644 InvisPopup.cs create mode 100644 InvisPopup.resx diff --git a/InvisPopup.Designer.cs b/InvisPopup.Designer.cs new file mode 100644 index 00000000..a40615f7 --- /dev/null +++ b/InvisPopup.Designer.cs @@ -0,0 +1,46 @@ +namespace VRCX +{ + partial class InvisPopup + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // Popup + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(148, 0); + this.Name = "Popup"; + this.Text = "Popup"; + this.ResumeLayout(false); + + } + + #endregion + } +} \ No newline at end of file diff --git a/InvisPopup.cs b/InvisPopup.cs new file mode 100644 index 00000000..8a4ad712 --- /dev/null +++ b/InvisPopup.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace VRCX +{ + public partial class InvisPopup : Form + { + public InvisPopup() + { + InitializeComponent(); + } + + protected override void SetVisibleCore(bool value) + { + this.WindowState = FormWindowState.Minimized; + base.SetVisibleCore(value); + } + } +} diff --git a/InvisPopup.resx b/InvisPopup.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/InvisPopup.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index e40d3c8e..ef299ac6 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -39,34 +39,37 @@ namespace VRCX this.TrayMenu_Separator = new System.Windows.Forms.ToolStripSeparator(); this.TrayMenu_Quit = new System.Windows.Forms.ToolStripMenuItem(); this.TrayIcon = new System.Windows.Forms.NotifyIcon(this.components); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); this.TrayMenu.SuspendLayout(); this.SuspendLayout(); // // TrayMenu // + this.TrayMenu.ImageScalingSize = new System.Drawing.Size(20, 20); this.TrayMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.TrayMenu_Open, this.TrayMenu_Separator, this.TrayMenu_Quit}); this.TrayMenu.Name = "TrayMenu"; - this.TrayMenu.Size = new System.Drawing.Size(132, 54); + this.TrayMenu.Size = new System.Drawing.Size(147, 58); // // TrayMenu_Open // this.TrayMenu_Open.Name = "TrayMenu_Open"; - this.TrayMenu_Open.Size = new System.Drawing.Size(131, 22); + this.TrayMenu_Open.Size = new System.Drawing.Size(146, 24); this.TrayMenu_Open.Text = "Open"; this.TrayMenu_Open.Click += new System.EventHandler(this.TrayMenu_Open_Click); // // TrayMenu_Separator // this.TrayMenu_Separator.Name = "TrayMenu_Separator"; - this.TrayMenu_Separator.Size = new System.Drawing.Size(128, 6); + this.TrayMenu_Separator.Size = new System.Drawing.Size(143, 6); // // TrayMenu_Quit // this.TrayMenu_Quit.Name = "TrayMenu_Quit"; - this.TrayMenu_Quit.Size = new System.Drawing.Size(131, 22); + this.TrayMenu_Quit.Size = new System.Drawing.Size(146, 24); this.TrayMenu_Quit.Text = "Quit VRCX"; this.TrayMenu_Quit.Click += new System.EventHandler(this.TrayMenu_Quit_Click); // @@ -77,12 +80,35 @@ namespace VRCX this.TrayIcon.Visible = true; this.TrayIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.TrayIcon_MouseDoubleClick); // + // button1 + // + this.button1.Location = new System.Drawing.Point(91, 81); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 1; + this.button1.Text = "Dark"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // button2 + // + this.button2.Location = new System.Drawing.Point(196, 81); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.TabIndex = 2; + this.button2.Text = "Light"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // // MainForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(842, 561); - this.MinimumSize = new System.Drawing.Size(320, 240); + this.ClientSize = new System.Drawing.Size(1052, 701); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.MinimumSize = new System.Drawing.Size(396, 288); this.Name = "MainForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "VRCX"; @@ -103,5 +129,7 @@ namespace VRCX private System.Windows.Forms.ToolStripSeparator TrayMenu_Separator; private System.Windows.Forms.ToolStripMenuItem TrayMenu_Quit; private System.Windows.Forms.NotifyIcon TrayIcon; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; } } \ No newline at end of file diff --git a/MainForm.cs b/MainForm.cs index 19b1a47c..d70fdb6f 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -169,5 +169,15 @@ namespace VRCX { Application.Exit(); } + + private void button1_Click(object sender, EventArgs e) + { + WinformThemer.SetGlobalTheme(1); + } + + private void button2_Click(object sender, EventArgs e) + { + WinformThemer.SetGlobalTheme(0); + } } } diff --git a/VRCX.csproj b/VRCX.csproj index 5cde8085..08b96366 100644 --- a/VRCX.csproj +++ b/VRCX.csproj @@ -83,6 +83,12 @@ + + Form + + + InvisPopup.cs + @@ -123,6 +129,9 @@ Form + + InvisPopup.cs + VRForm.cs diff --git a/WinformThemer.cs b/WinformThemer.cs index c89078d3..77710e85 100644 --- a/WinformThemer.cs +++ b/WinformThemer.cs @@ -13,12 +13,6 @@ namespace VRCX 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; /// @@ -29,7 +23,14 @@ namespace VRCX public static void SetGlobalTheme(int theme) { currentTheme = theme; - foreach (Form form in Application.OpenForms) + + List
forms = new List(); + foreach(Form form in Application.OpenForms) + { + forms.Add(form); + } + + foreach (Form form in forms) { SetThemeToGlobal(form); } @@ -45,14 +46,32 @@ namespace VRCX public static void SetThemeToGlobal(Form form) { SetThemeToGlobal(form.Handle); + + InvisPopup thisJankThing = new InvisPopup(); + thisJankThing.Show(); + + if (form.WindowState != FormWindowState.Minimized) + { + //attempting to refresh this god forsaken title bar + + //Minimize, Downside: shows animation + //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_MINIMIZE); + //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_RESTORE); + + //Hide, Downside: reorders window to last in taskbar if not pinned + PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_HIDE); + PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_SHOW); + } + + thisJankThing.Close(); } private static void SetThemeToGlobal(IntPtr handle) { if (GetTheme(handle) != currentTheme) { - if (DwmSetWindowAttribute(handle, 19, new[] { currentTheme }, 4) != 0) - DwmSetWindowAttribute(handle, 20, new[] { currentTheme }, 4); + if (PInvokeFun.DwmSetWindowAttribute(handle, 19, new[] { currentTheme }, 4) != 0) + PInvokeFun.DwmSetWindowAttribute(handle, 20, new[] { currentTheme }, 4); } } @@ -62,8 +81,8 @@ namespace VRCX IntPtr curThemePtr = Marshal.AllocHGlobal(4); //See what window state it currently is - if (DwmGetWindowAttribute(handle, 19, curThemePtr, 4) != 0) - DwmGetWindowAttribute(handle, 20, curThemePtr, 4); + if (PInvokeFun.DwmGetWindowAttribute(handle, 19, curThemePtr, 4) != 0) + PInvokeFun.DwmGetWindowAttribute(handle, 20, curThemePtr, 4); //Read current theme (light = 0, dark = 1) int theme = Marshal.ReadInt32(curThemePtr); @@ -73,5 +92,32 @@ namespace VRCX return theme; } + + internal static class PInvokeFun + { + [DllImport("DwmApi")] + internal static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, int[] pvAttribute, int cbAttribute); + + [DllImport("DwmApi")] + internal static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, IntPtr pvAttribute, int cbAttribute); + + [DllImport("user32.dll")] + internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + internal enum SW_TYPES + { + SW_HIDE = 0, + SW_SHOWNORMAL = 1, + SW_SHOWMINIMIZED = 2, + SW_SHOWMAXIMIZED = 3, + SW_SHOWNOACTIVATE = 4, + SW_SHOW = 5, + SW_MINIMIZE = 6, + SW_SHOWMINNOACTIVE = 7, + SW_SHOWNA = 8, + SW_RESTORE = 9, + SW_SHOWDEFAULT = 10, + SW_FORCEMINIMIZE = 11 + } + } } } From 2e88c971789720d205d21181b59a6631ffea6f09 Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Wed, 23 Mar 2022 22:25:08 -0400 Subject: [PATCH 03/11] Cleanup of WinformThemer --- WinformThemer.cs | 57 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/WinformThemer.cs b/WinformThemer.cs index 77710e85..fd13f3c6 100644 --- a/WinformThemer.cs +++ b/WinformThemer.cs @@ -29,11 +29,7 @@ namespace VRCX { forms.Add(form); } - - foreach (Form form in forms) - { - SetThemeToGlobal(form); - } + SetThemeToGlobal(forms); } /// @@ -43,27 +39,35 @@ namespace VRCX /// public static int GetGlobalTheme() => currentTheme; + public static void SetThemeToGlobal(Form form) { - SetThemeToGlobal(form.Handle); + SetThemeToGlobal(new List() { form }); + } - InvisPopup thisJankThing = new InvisPopup(); - thisJankThing.Show(); + public static void SetThemeToGlobal(List forms) + { + InvisPopupHandler.Show(); - if (form.WindowState != FormWindowState.Minimized) + foreach(Form form in forms) { - //attempting to refresh this god forsaken title bar + SetThemeToGlobal(form.Handle); - //Minimize, Downside: shows animation - //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_MINIMIZE); - //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_RESTORE); + if (form.WindowState != FormWindowState.Minimized) + { + //attempting to refresh this god forsaken title bar - //Hide, Downside: reorders window to last in taskbar if not pinned - PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_HIDE); - PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_SHOW); + //Minimize, Downside: shows animation + //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_MINIMIZE); + //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_RESTORE); + + //Hide, Downside: reorders window to last in taskbar if not pinned + PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_HIDE); + PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_SHOW); + } } - thisJankThing.Close(); + InvisPopupHandler.Close(); } private static void SetThemeToGlobal(IntPtr handle) @@ -93,6 +97,25 @@ namespace VRCX return theme; } + internal static class InvisPopupHandler + { + private static InvisPopup instance; + + internal static void Show() + { + if(instance == null) + instance = new InvisPopup(); + instance.Show(); + } + + internal static void Close() + { + instance.Close(); + instance.Dispose(); + instance = null; + } + } + internal static class PInvokeFun { [DllImport("DwmApi")] From fd360ef9f999828ea0380bceae557201a1f448a8 Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Wed, 23 Mar 2022 22:29:42 -0400 Subject: [PATCH 04/11] Removing debug from MainForm --- MainForm.Designer.cs | 42 +++++++----------------------------------- MainForm.cs | 10 ---------- 2 files changed, 7 insertions(+), 45 deletions(-) diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index ef299ac6..e40d3c8e 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -39,37 +39,34 @@ namespace VRCX this.TrayMenu_Separator = new System.Windows.Forms.ToolStripSeparator(); this.TrayMenu_Quit = new System.Windows.Forms.ToolStripMenuItem(); this.TrayIcon = new System.Windows.Forms.NotifyIcon(this.components); - this.button1 = new System.Windows.Forms.Button(); - this.button2 = new System.Windows.Forms.Button(); this.TrayMenu.SuspendLayout(); this.SuspendLayout(); // // TrayMenu // - this.TrayMenu.ImageScalingSize = new System.Drawing.Size(20, 20); this.TrayMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.TrayMenu_Open, this.TrayMenu_Separator, this.TrayMenu_Quit}); this.TrayMenu.Name = "TrayMenu"; - this.TrayMenu.Size = new System.Drawing.Size(147, 58); + this.TrayMenu.Size = new System.Drawing.Size(132, 54); // // TrayMenu_Open // this.TrayMenu_Open.Name = "TrayMenu_Open"; - this.TrayMenu_Open.Size = new System.Drawing.Size(146, 24); + this.TrayMenu_Open.Size = new System.Drawing.Size(131, 22); this.TrayMenu_Open.Text = "Open"; this.TrayMenu_Open.Click += new System.EventHandler(this.TrayMenu_Open_Click); // // TrayMenu_Separator // this.TrayMenu_Separator.Name = "TrayMenu_Separator"; - this.TrayMenu_Separator.Size = new System.Drawing.Size(143, 6); + this.TrayMenu_Separator.Size = new System.Drawing.Size(128, 6); // // TrayMenu_Quit // this.TrayMenu_Quit.Name = "TrayMenu_Quit"; - this.TrayMenu_Quit.Size = new System.Drawing.Size(146, 24); + this.TrayMenu_Quit.Size = new System.Drawing.Size(131, 22); this.TrayMenu_Quit.Text = "Quit VRCX"; this.TrayMenu_Quit.Click += new System.EventHandler(this.TrayMenu_Quit_Click); // @@ -80,35 +77,12 @@ namespace VRCX this.TrayIcon.Visible = true; this.TrayIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.TrayIcon_MouseDoubleClick); // - // button1 - // - this.button1.Location = new System.Drawing.Point(91, 81); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); - this.button1.TabIndex = 1; - this.button1.Text = "Dark"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // button2 - // - this.button2.Location = new System.Drawing.Point(196, 81); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(75, 23); - this.button2.TabIndex = 2; - this.button2.Text = "Light"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.button2_Click); - // // MainForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(1052, 701); - this.Controls.Add(this.button2); - this.Controls.Add(this.button1); - this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); - this.MinimumSize = new System.Drawing.Size(396, 288); + this.ClientSize = new System.Drawing.Size(842, 561); + this.MinimumSize = new System.Drawing.Size(320, 240); this.Name = "MainForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "VRCX"; @@ -129,7 +103,5 @@ namespace VRCX private System.Windows.Forms.ToolStripSeparator TrayMenu_Separator; private System.Windows.Forms.ToolStripMenuItem TrayMenu_Quit; private System.Windows.Forms.NotifyIcon TrayIcon; - private System.Windows.Forms.Button button1; - private System.Windows.Forms.Button button2; } } \ No newline at end of file diff --git a/MainForm.cs b/MainForm.cs index d70fdb6f..19b1a47c 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -169,15 +169,5 @@ namespace VRCX { Application.Exit(); } - - private void button1_Click(object sender, EventArgs e) - { - WinformThemer.SetGlobalTheme(1); - } - - private void button2_Click(object sender, EventArgs e) - { - WinformThemer.SetGlobalTheme(0); - } } } From abc08e6bdedb452177c9dced0de31cc3b1efff78 Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Wed, 23 Mar 2022 22:39:21 -0400 Subject: [PATCH 05/11] Preventing redundency in SetGlobalTheme --- WinformThemer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WinformThemer.cs b/WinformThemer.cs index fd13f3c6..a4749fd9 100644 --- a/WinformThemer.cs +++ b/WinformThemer.cs @@ -22,6 +22,9 @@ namespace VRCX ///
public static void SetGlobalTheme(int theme) { + if(currentTheme == theme) + return; + currentTheme = theme; List forms = new List(); From 01cb6ca0e124ff636b951f1df0d73d0b89ecf3a3 Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Thu, 24 Mar 2022 01:19:04 -0400 Subject: [PATCH 06/11] Possibly fixed bug of occasionaly Taskbar order change --- WinformThemer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/WinformThemer.cs b/WinformThemer.cs index a4749fd9..4bbf9a2e 100644 --- a/WinformThemer.cs +++ b/WinformThemer.cs @@ -109,6 +109,7 @@ namespace VRCX if(instance == null) instance = new InvisPopup(); instance.Show(); + instance.Activate(); } internal static void Close() From ea581a2420fced533ce518760668387c9fd195a2 Mon Sep 17 00:00:00 2001 From: Natsumi Date: Thu, 24 Mar 2022 19:12:02 +1300 Subject: [PATCH 07/11] Apply title bar colour on theme change --- AppApi.cs | 5 +++++ html/src/app.js | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/AppApi.cs b/AppApi.cs index ae676c02..2dc14060 100644 --- a/AppApi.cs +++ b/AppApi.cs @@ -415,6 +415,11 @@ namespace VRCX return System.Globalization.CultureInfo.CurrentCulture.ToString(); } + public void ChangeTheme(int value) + { + WinformThemer.SetGlobalTheme(value); + } + public void SetStartup(bool enabled) { try diff --git a/html/src/app.js b/html/src/app.js index b89e03d4..41978a7e 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -11397,8 +11397,18 @@ speechSynthesis.getVoices(); $app.watch.isDarkMode = function () { configRepository.setBool('isDarkMode', this.isDarkMode); $appDarkStyle.disabled = this.isDarkMode === false; + if (this.isDarkMode) { + AppApi.ChangeTheme(1); + } else { + AppApi.ChangeTheme(0); + } this.updateVRConfigVars(); }; + if ($app.data.isDarkMode) { + AppApi.ChangeTheme(1); + } else { + AppApi.ChangeTheme(0); + } window .matchMedia('(prefers-color-scheme: dark)') .addEventListener('change', (e) => { From a41d65a43809bf3f529774520ba28eb551613bd8 Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Thu, 24 Mar 2022 02:27:57 -0400 Subject: [PATCH 08/11] Second attempt to fix random Taskbar reorder issue --- InvisPopup.Designer.cs | 7 ++++--- InvisPopup.cs | 12 +++++++----- WinformThemer.cs | 29 ++++++++++++++++++++--------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/InvisPopup.Designer.cs b/InvisPopup.Designer.cs index a40615f7..1ae7d0e6 100644 --- a/InvisPopup.Designer.cs +++ b/InvisPopup.Designer.cs @@ -30,13 +30,14 @@ { this.SuspendLayout(); // - // Popup + // InvisPopup // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(148, 0); - this.Name = "Popup"; - this.Text = "Popup"; + this.Name = "InvisPopup"; + this.Opacity = 0D; + this.Text = "InvisPopup"; this.ResumeLayout(false); } diff --git a/InvisPopup.cs b/InvisPopup.cs index 8a4ad712..e2afc247 100644 --- a/InvisPopup.cs +++ b/InvisPopup.cs @@ -14,13 +14,15 @@ namespace VRCX { public InvisPopup() { + StartPosition = FormStartPosition.Manual; + //Location = new Point(-Height - 100, 0); + Location = new Point(0, 0); InitializeComponent(); } - protected override void SetVisibleCore(bool value) - { - this.WindowState = FormWindowState.Minimized; - base.SetVisibleCore(value); - } + //protected override void SetVisibleCore(bool value) + //{ + // base.SetVisibleCore(value); + //} } } diff --git a/WinformThemer.cs b/WinformThemer.cs index 4bbf9a2e..69ee6f8e 100644 --- a/WinformThemer.cs +++ b/WinformThemer.cs @@ -22,8 +22,8 @@ namespace VRCX /// public static void SetGlobalTheme(int theme) { - if(currentTheme == theme) - return; + //if(currentTheme == theme) + // return; currentTheme = theme; @@ -50,14 +50,15 @@ namespace VRCX public static void SetThemeToGlobal(List forms) { + var activeForm = Form.ActiveForm; InvisPopupHandler.Show(); foreach(Form form in forms) { SetThemeToGlobal(form.Handle); - - if (form.WindowState != FormWindowState.Minimized) - { + form.Activate(); + //if (form.WindowState != FormWindowState.Minimized) + //{ //attempting to refresh this god forsaken title bar //Minimize, Downside: shows animation @@ -65,12 +66,13 @@ namespace VRCX //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_RESTORE); //Hide, Downside: reorders window to last in taskbar if not pinned - PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_HIDE); - PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_SHOW); - } + //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_HIDE); + //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_SHOW); + //} } - InvisPopupHandler.Close(); + if(activeForm != null) + activeForm.Activate(); } private static void SetThemeToGlobal(IntPtr handle) @@ -110,6 +112,11 @@ namespace VRCX instance = new InvisPopup(); instance.Show(); instance.Activate(); + //PInvokeFun.ShowWindow(instance.Handle, (int)PInvokeFun.SW_TYPES.SW_SHOWNORMAL); + //PInvokeFun.SetForegroundWindow(instance.Handle); + //instance.Hide(); + //instance.Show(); + //instance.Activate(); } internal static void Close() @@ -130,6 +137,10 @@ namespace VRCX [DllImport("user32.dll")] internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool SetForegroundWindow(IntPtr hwnd); + internal enum SW_TYPES { SW_HIDE = 0, From 1b35dbe4648c956c8d0dcf1897a3ae46de2a6190 Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Thu, 24 Mar 2022 02:42:51 -0400 Subject: [PATCH 09/11] Cleanup + Some commenting to explain code --- InvisPopup.cs | 6 ---- WinformThemer.cs | 80 +++++++++++++++++++----------------------------- 2 files changed, 31 insertions(+), 55 deletions(-) diff --git a/InvisPopup.cs b/InvisPopup.cs index e2afc247..a26c411c 100644 --- a/InvisPopup.cs +++ b/InvisPopup.cs @@ -15,14 +15,8 @@ namespace VRCX public InvisPopup() { StartPosition = FormStartPosition.Manual; - //Location = new Point(-Height - 100, 0); Location = new Point(0, 0); InitializeComponent(); } - - //protected override void SetVisibleCore(bool value) - //{ - // base.SetVisibleCore(value); - //} } } diff --git a/WinformThemer.cs b/WinformThemer.cs index 69ee6f8e..a9b141ef 100644 --- a/WinformThemer.cs +++ b/WinformThemer.cs @@ -13,6 +13,9 @@ namespace VRCX internal static class WinformThemer { + /// + /// Private holder of current theme + /// private static int currentTheme = 0; /// @@ -22,16 +25,15 @@ namespace VRCX /// public static void SetGlobalTheme(int theme) { - //if(currentTheme == theme) - // return; - currentTheme = theme; + //Make a seperate list for all current forms (causes issues otherwise) List forms = new List(); foreach(Form form in Application.OpenForms) { forms.Add(form); } + SetThemeToGlobal(forms); } @@ -42,36 +44,43 @@ namespace VRCX /// public static int GetGlobalTheme() => currentTheme; - + /// + /// Set given form to the current global theme + /// + /// public static void SetThemeToGlobal(Form form) { SetThemeToGlobal(new List() { form }); } + /// + /// Set a list of given forms to the current global theme + /// + /// public static void SetThemeToGlobal(List forms) { + //Save current active form so we can refocus on this at the end var activeForm = Form.ActiveForm; + + //Show and focus on the invisible popup InvisPopupHandler.Show(); + //For each form, set the theme, then move focus onto it to force refresh foreach(Form form in forms) { + //Set the theme of the window SetThemeToGlobal(form.Handle); - form.Activate(); - //if (form.WindowState != FormWindowState.Minimized) - //{ - //attempting to refresh this god forsaken title bar - //Minimize, Downside: shows animation - //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_MINIMIZE); - //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_RESTORE); - - //Hide, Downside: reorders window to last in taskbar if not pinned - //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_HIDE); - //PInvokeFun.ShowWindow(form.Handle, (int)PInvokeFun.SW_TYPES.SW_SHOW); - //} + //Move focus onto it to force refresh if not minimized + if (form.WindowState != FormWindowState.Minimized) + form.Activate(); } + + //Close + Dispose the invisible popup InvisPopupHandler.Close(); - if(activeForm != null) + + //Restore focus to previous active form + if(activeForm != null && activeForm.WindowState != FormWindowState.Minimized) activeForm.Activate(); } @@ -79,8 +88,8 @@ namespace VRCX { if (GetTheme(handle) != currentTheme) { - if (PInvokeFun.DwmSetWindowAttribute(handle, 19, new[] { currentTheme }, 4) != 0) - PInvokeFun.DwmSetWindowAttribute(handle, 20, new[] { currentTheme }, 4); + if (PInvoke.DwmSetWindowAttribute(handle, 19, new[] { currentTheme }, 4) != 0) + PInvoke.DwmSetWindowAttribute(handle, 20, new[] { currentTheme }, 4); } } @@ -90,8 +99,8 @@ namespace VRCX IntPtr curThemePtr = Marshal.AllocHGlobal(4); //See what window state it currently is - if (PInvokeFun.DwmGetWindowAttribute(handle, 19, curThemePtr, 4) != 0) - PInvokeFun.DwmGetWindowAttribute(handle, 20, curThemePtr, 4); + if (PInvoke.DwmGetWindowAttribute(handle, 19, curThemePtr, 4) != 0) + PInvoke.DwmGetWindowAttribute(handle, 20, curThemePtr, 4); //Read current theme (light = 0, dark = 1) int theme = Marshal.ReadInt32(curThemePtr); @@ -112,11 +121,6 @@ namespace VRCX instance = new InvisPopup(); instance.Show(); instance.Activate(); - //PInvokeFun.ShowWindow(instance.Handle, (int)PInvokeFun.SW_TYPES.SW_SHOWNORMAL); - //PInvokeFun.SetForegroundWindow(instance.Handle); - //instance.Hide(); - //instance.Show(); - //instance.Activate(); } internal static void Close() @@ -127,35 +131,13 @@ namespace VRCX } } - internal static class PInvokeFun + internal static class PInvoke { [DllImport("DwmApi")] internal static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, int[] pvAttribute, int cbAttribute); [DllImport("DwmApi")] internal static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, IntPtr pvAttribute, int cbAttribute); - - [DllImport("user32.dll")] - internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); - - [DllImport("user32.dll", SetLastError = true)] - internal static extern bool SetForegroundWindow(IntPtr hwnd); - - internal enum SW_TYPES - { - SW_HIDE = 0, - SW_SHOWNORMAL = 1, - SW_SHOWMINIMIZED = 2, - SW_SHOWMAXIMIZED = 3, - SW_SHOWNOACTIVATE = 4, - SW_SHOW = 5, - SW_MINIMIZE = 6, - SW_SHOWMINNOACTIVE = 7, - SW_SHOWNA = 8, - SW_RESTORE = 9, - SW_SHOWDEFAULT = 10, - SW_FORCEMINIMIZE = 11 - } } } } From 8d1701ffb8a5c2219d1ae84ccb126a17e156e7c2 Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Thu, 24 Mar 2022 03:09:17 -0400 Subject: [PATCH 10/11] Move popup to -Width, -Height --- InvisPopup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvisPopup.cs b/InvisPopup.cs index a26c411c..d3017894 100644 --- a/InvisPopup.cs +++ b/InvisPopup.cs @@ -15,7 +15,7 @@ namespace VRCX public InvisPopup() { StartPosition = FormStartPosition.Manual; - Location = new Point(0, 0); + Location = new Point(-Width, -Height); InitializeComponent(); } } From ce9ab560fe04cfa58f71ed7bbeb4ba8db608b8be Mon Sep 17 00:00:00 2001 From: Usman Shafiq Date: Thu, 24 Mar 2022 10:54:27 -0400 Subject: [PATCH 11/11] Replaced InvisPopup with Opacity to force redraw --- InvisPopup.Designer.cs | 47 ---------------- InvisPopup.cs | 22 -------- InvisPopup.resx | 120 ----------------------------------------- VRCX.csproj | 9 ---- WinformThemer.cs | 39 ++------------ 5 files changed, 3 insertions(+), 234 deletions(-) delete mode 100644 InvisPopup.Designer.cs delete mode 100644 InvisPopup.cs delete mode 100644 InvisPopup.resx diff --git a/InvisPopup.Designer.cs b/InvisPopup.Designer.cs deleted file mode 100644 index 1ae7d0e6..00000000 --- a/InvisPopup.Designer.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace VRCX -{ - partial class InvisPopup - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.SuspendLayout(); - // - // InvisPopup - // - this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(148, 0); - this.Name = "InvisPopup"; - this.Opacity = 0D; - this.Text = "InvisPopup"; - this.ResumeLayout(false); - - } - - #endregion - } -} \ No newline at end of file diff --git a/InvisPopup.cs b/InvisPopup.cs deleted file mode 100644 index d3017894..00000000 --- a/InvisPopup.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace VRCX -{ - public partial class InvisPopup : Form - { - public InvisPopup() - { - StartPosition = FormStartPosition.Manual; - Location = new Point(-Width, -Height); - InitializeComponent(); - } - } -} diff --git a/InvisPopup.resx b/InvisPopup.resx deleted file mode 100644 index 1af7de15..00000000 --- a/InvisPopup.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/VRCX.csproj b/VRCX.csproj index 08b96366..5cde8085 100644 --- a/VRCX.csproj +++ b/VRCX.csproj @@ -83,12 +83,6 @@ - - Form - - - InvisPopup.cs - @@ -129,9 +123,6 @@ Form - - InvisPopup.cs - VRForm.cs diff --git a/WinformThemer.cs b/WinformThemer.cs index a9b141ef..057908d7 100644 --- a/WinformThemer.cs +++ b/WinformThemer.cs @@ -59,29 +59,16 @@ namespace VRCX /// public static void SetThemeToGlobal(List forms) { - //Save current active form so we can refocus on this at the end - var activeForm = Form.ActiveForm; - - //Show and focus on the invisible popup - InvisPopupHandler.Show(); - //For each form, set the theme, then move focus onto it to force refresh foreach(Form form in forms) { //Set the theme of the window SetThemeToGlobal(form.Handle); - //Move focus onto it to force refresh if not minimized - if (form.WindowState != FormWindowState.Minimized) - form.Activate(); + //Change opacity to foce full redraw + form.Opacity = 0.99999; + form.Opacity = 1; } - - //Close + Dispose the invisible popup - InvisPopupHandler.Close(); - - //Restore focus to previous active form - if(activeForm != null && activeForm.WindowState != FormWindowState.Minimized) - activeForm.Activate(); } private static void SetThemeToGlobal(IntPtr handle) @@ -111,26 +98,6 @@ namespace VRCX return theme; } - internal static class InvisPopupHandler - { - private static InvisPopup instance; - - internal static void Show() - { - if(instance == null) - instance = new InvisPopup(); - instance.Show(); - instance.Activate(); - } - - internal static void Close() - { - instance.Close(); - instance.Dispose(); - instance = null; - } - } - internal static class PInvoke { [DllImport("DwmApi")]