From ecaaa044a8865f752fcd5c90e363ddd1e7432c74 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 17:57:13 +0000 Subject: [PATCH 1/9] Initial plan From 91ecf68cf99ee9f42803e24fded7526a478e6f2a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:01:52 +0000 Subject: [PATCH 2/9] Add OS theme detection and support for main window Co-authored-by: lsd-techno <6795932+lsd-techno@users.noreply.github.com> --- MainForm.Designer.cs | 5 +- MainForm.cs | 153 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 2 deletions(-) diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index fcd6da3..79a5115 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -17,6 +17,9 @@ protected override void Dispose(bool disposing) components.Dispose(); autoRefreshTimer?.Dispose(); clickTimer?.Dispose(); + + // Unsubscribe from system theme changes + Microsoft.Win32.SystemEvents.UserPreferenceChanged -= OnSystemThemeChanged; } base.Dispose(disposing); } @@ -91,7 +94,6 @@ private void InitializeComponent() // // contextMenuStrip1 // - contextMenuStrip1.BackColor = SystemColors.ButtonShadow; contextMenuStrip1.Items.AddRange(new ToolStripItem[] { mainToolStripMenuItem, startHiddenMenu, autoAlterMenu, refreshIntervalMenu, autoStartMenu, toolStripSeparator1, exitToolStripMenuItem }); contextMenuStrip1.Name = "contextMenuStrip1"; contextMenuStrip1.Size = new Size(181, 164); @@ -491,7 +493,6 @@ private void InitializeComponent() AutoScaleMode = AutoScaleMode.Font; AutoSize = true; AutoSizeMode = AutoSizeMode.GrowAndShrink; - BackColor = SystemColors.ButtonShadow; ClientSize = new Size(800, 450); Controls.Add(groupBoxNative); Controls.Add(trackBarToggle); diff --git a/MainForm.cs b/MainForm.cs index 620592d..980df7a 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -24,6 +24,13 @@ public partial class MainForm : Form public MainForm() { InitializeComponent(); + + // Apply initial theme before any other UI operations + ApplyThemeToMainForm(); + + // Subscribe to system theme changes + Microsoft.Win32.SystemEvents.UserPreferenceChanged += OnSystemThemeChanged; + isAutoStartOn = AppAutoStart.GetAutoStart(); autoStartMenu.Checked = isAutoStartOn; @@ -427,6 +434,152 @@ private void UpdateContextMenuTheme(ContextMenuStrip contextMenu) contextMenu.Renderer = IsLightThemeEnabled() ? new ToolStripProfessionalRenderer() : new DarkModeToolStripRenderer(); } + private void ApplyThemeToMainForm() + { + bool isLightTheme = IsLightThemeEnabled(); + + // Set form colors + if (isLightTheme) + { + this.BackColor = SystemColors.Control; + this.ForeColor = SystemColors.ControlText; + } + else + { + this.BackColor = Color.FromArgb(32, 32, 32); + this.ForeColor = Color.LightGray; + } + + // Apply theme to all group boxes + ApplyThemeToGroupBox(groupBoxNative, isLightTheme); + ApplyThemeToGroupBox(groupBoxAlterNative, isLightTheme); + ApplyThemeToGroupBox(groupBoxCurrent, isLightTheme); + + // Apply theme to trackbar + ApplyThemeToTrackBar(trackBarToggle, isLightTheme); + } + + private void ApplyThemeToGroupBox(GroupBox groupBox, bool isLightTheme) + { + if (groupBox == null) return; + + if (isLightTheme) + { + groupBox.BackColor = SystemColors.Control; + groupBox.ForeColor = SystemColors.ControlText; + } + else + { + groupBox.BackColor = Color.FromArgb(45, 45, 45); + groupBox.ForeColor = Color.LightGray; + } + + // Apply theme to all controls within the group box + foreach (Control control in groupBox.Controls) + { + ApplyThemeToControl(control, isLightTheme); + } + } + + private void ApplyThemeToControl(Control control, bool isLightTheme) + { + if (control is TextBox textBox) + { + if (isLightTheme) + { + textBox.BackColor = SystemColors.Window; + textBox.ForeColor = SystemColors.WindowText; + } + else + { + textBox.BackColor = Color.FromArgb(55, 55, 55); + textBox.ForeColor = Color.LightGray; + } + } + else if (control is Button button) + { + if (isLightTheme) + { + button.BackColor = SystemColors.Control; + button.ForeColor = SystemColors.ControlText; + button.FlatStyle = FlatStyle.Standard; + } + else + { + button.BackColor = Color.FromArgb(60, 60, 60); + button.ForeColor = Color.LightGray; + button.FlatStyle = FlatStyle.Flat; + button.FlatAppearance.BorderColor = Color.FromArgb(80, 80, 80); + } + } + else if (control is CheckBox checkBox) + { + if (isLightTheme) + { + checkBox.ForeColor = SystemColors.ControlText; + } + else + { + checkBox.ForeColor = Color.LightGray; + } + } + else if (control is Label label) + { + if (isLightTheme) + { + label.ForeColor = SystemColors.ControlText; + } + else + { + label.ForeColor = Color.LightGray; + } + } + else if (control is NumericUpDown numericUpDown) + { + if (isLightTheme) + { + numericUpDown.BackColor = SystemColors.Window; + numericUpDown.ForeColor = SystemColors.WindowText; + } + else + { + numericUpDown.BackColor = Color.FromArgb(55, 55, 55); + numericUpDown.ForeColor = Color.LightGray; + } + } + } + + private void ApplyThemeToTrackBar(TrackBar trackBar, bool isLightTheme) + { + if (trackBar == null) return; + + if (isLightTheme) + { + trackBar.BackColor = SystemColors.Control; + } + else + { + trackBar.BackColor = Color.FromArgb(32, 32, 32); + } + } + + private void OnSystemThemeChanged(object sender, Microsoft.Win32.UserPreferenceChangedEventArgs e) + { + // Only respond to theme changes + if (e.Category == Microsoft.Win32.UserPreferenceCategory.General) + { + // Apply the new theme + if (this.InvokeRequired) + { + this.BeginInvoke(new Action(() => ApplyThemeToMainForm())); + } + else + { + ApplyThemeToMainForm(); + } + } + } + private void autoStartMenu_Click(object sender, EventArgs e) { // Toggle the auto-start setting based on its current state From 7fcbe90d0dbaf6fc9b0c594b4e172dd875c05b8d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:03:11 +0000 Subject: [PATCH 3/9] Update README to reflect enhanced OS theme support Co-authored-by: lsd-techno <6795932+lsd-techno@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c72d6a..f53c203 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ GateSwitchWay is a simple Windows desktop application that allows users to switc - **Start Hidden**: Option to start the application minimized to the system tray. - **Auto Alter**: Automatically switch to the alternative network settings on startup. - **System Tray Integration**: Control the application from the system tray with single and double-click actions. -- **Dark Mode Support**: Context menu adapts to the system's light or dark theme. +- **OS Theme Support**: Main window and context menu automatically adapt to the system's light or dark theme, with real-time theme change detection. > Note: This fork is an experiment to have the repository largely maintained by a supervised Copilot (AI-assisted). Human reviewers will supervise and review changes before merging. Contributions are welcome; please follow the contribution guidelines. From 61f9c1ddb0e176da43e7b04a59e2aa5901b67872 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:05:13 +0000 Subject: [PATCH 4/9] Refactor theme colors to use named constants for better maintainability Co-authored-by: lsd-techno <6795932+lsd-techno@users.noreply.github.com> --- MainForm.cs | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/MainForm.cs b/MainForm.cs index 980df7a..f07d4a5 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -15,6 +15,14 @@ public partial class MainForm : Form private static bool isLoadingSettings = false; private static bool isAutoAlterOn = false; + // Dark mode color constants + private static readonly Color DarkFormBackground = Color.FromArgb(32, 32, 32); + private static readonly Color DarkGroupBoxBackground = Color.FromArgb(45, 45, 45); + private static readonly Color DarkControlBackground = Color.FromArgb(55, 55, 55); + private static readonly Color DarkButtonBackground = Color.FromArgb(60, 60, 60); + private static readonly Color DarkButtonBorder = Color.FromArgb(80, 80, 80); + private static readonly Color DarkForeground = Color.LightGray; + private NetworkHelper.NetworkInfo currentNetworkInfo; private NetworkHelper.NetworkInfo alternativeNetworkInfo; @@ -446,8 +454,8 @@ private void ApplyThemeToMainForm() } else { - this.BackColor = Color.FromArgb(32, 32, 32); - this.ForeColor = Color.LightGray; + this.BackColor = DarkFormBackground; + this.ForeColor = DarkForeground; } // Apply theme to all group boxes @@ -470,8 +478,8 @@ private void ApplyThemeToGroupBox(GroupBox groupBox, bool isLightTheme) } else { - groupBox.BackColor = Color.FromArgb(45, 45, 45); - groupBox.ForeColor = Color.LightGray; + groupBox.BackColor = DarkGroupBoxBackground; + groupBox.ForeColor = DarkForeground; } // Apply theme to all controls within the group box @@ -492,8 +500,8 @@ private void ApplyThemeToControl(Control control, bool isLightTheme) } else { - textBox.BackColor = Color.FromArgb(55, 55, 55); - textBox.ForeColor = Color.LightGray; + textBox.BackColor = DarkControlBackground; + textBox.ForeColor = DarkForeground; } } else if (control is Button button) @@ -506,10 +514,10 @@ private void ApplyThemeToControl(Control control, bool isLightTheme) } else { - button.BackColor = Color.FromArgb(60, 60, 60); - button.ForeColor = Color.LightGray; + button.BackColor = DarkButtonBackground; + button.ForeColor = DarkForeground; button.FlatStyle = FlatStyle.Flat; - button.FlatAppearance.BorderColor = Color.FromArgb(80, 80, 80); + button.FlatAppearance.BorderColor = DarkButtonBorder; } } else if (control is CheckBox checkBox) @@ -520,7 +528,7 @@ private void ApplyThemeToControl(Control control, bool isLightTheme) } else { - checkBox.ForeColor = Color.LightGray; + checkBox.ForeColor = DarkForeground; } } else if (control is Label label) @@ -531,7 +539,7 @@ private void ApplyThemeToControl(Control control, bool isLightTheme) } else { - label.ForeColor = Color.LightGray; + label.ForeColor = DarkForeground; } } else if (control is NumericUpDown numericUpDown) @@ -543,8 +551,8 @@ private void ApplyThemeToControl(Control control, bool isLightTheme) } else { - numericUpDown.BackColor = Color.FromArgb(55, 55, 55); - numericUpDown.ForeColor = Color.LightGray; + numericUpDown.BackColor = DarkControlBackground; + numericUpDown.ForeColor = DarkForeground; } } } @@ -559,7 +567,7 @@ private void ApplyThemeToTrackBar(TrackBar trackBar, bool isLightTheme) } else { - trackBar.BackColor = Color.FromArgb(32, 32, 32); + trackBar.BackColor = DarkFormBackground; } } From f95c6f67f5d89abcdec1a4976594cdd958e0adc6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:07:24 +0000 Subject: [PATCH 5/9] Add hex comments to color constants and optimize theme change detection Co-authored-by: lsd-techno <6795932+lsd-techno@users.noreply.github.com> --- MainForm.cs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/MainForm.cs b/MainForm.cs index f07d4a5..1505ba4 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -16,16 +16,19 @@ public partial class MainForm : Form private static bool isAutoAlterOn = false; // Dark mode color constants - private static readonly Color DarkFormBackground = Color.FromArgb(32, 32, 32); - private static readonly Color DarkGroupBoxBackground = Color.FromArgb(45, 45, 45); - private static readonly Color DarkControlBackground = Color.FromArgb(55, 55, 55); - private static readonly Color DarkButtonBackground = Color.FromArgb(60, 60, 60); - private static readonly Color DarkButtonBorder = Color.FromArgb(80, 80, 80); + private static readonly Color DarkFormBackground = Color.FromArgb(32, 32, 32); // #202020 + private static readonly Color DarkGroupBoxBackground = Color.FromArgb(45, 45, 45); // #2D2D2D + private static readonly Color DarkControlBackground = Color.FromArgb(55, 55, 55); // #373737 + private static readonly Color DarkButtonBackground = Color.FromArgb(60, 60, 60); // #3C3C3C + private static readonly Color DarkButtonBorder = Color.FromArgb(80, 80, 80); // #505050 private static readonly Color DarkForeground = Color.LightGray; private NetworkHelper.NetworkInfo currentNetworkInfo; private NetworkHelper.NetworkInfo alternativeNetworkInfo; + // Track the last applied theme to avoid unnecessary reapplications + private bool? lastAppliedThemeWasLight = null; + // Auto-refresh timer for network status private System.Windows.Forms.Timer autoRefreshTimer = new System.Windows.Forms.Timer(); @@ -446,6 +449,14 @@ private void ApplyThemeToMainForm() { bool isLightTheme = IsLightThemeEnabled(); + // Only apply theme if it has actually changed to avoid unnecessary UI updates + if (lastAppliedThemeWasLight.HasValue && lastAppliedThemeWasLight.Value == isLightTheme) + { + return; + } + + lastAppliedThemeWasLight = isLightTheme; + // Set form colors if (isLightTheme) { From 3949152ca90b130e32a0022c55e0d837cf37fa5a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:09:05 +0000 Subject: [PATCH 6/9] Remove unused static field from IsLightThemeEnabled method Co-authored-by: lsd-techno <6795932+lsd-techno@users.noreply.github.com> --- MainForm.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/MainForm.cs b/MainForm.cs index 1505ba4..159f42e 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -408,13 +408,12 @@ private void ToggleSwitch() TrackBar_Set(isSwitchedOn); } - private static bool currentLightThemeEnabled = false; private bool IsLightThemeEnabled() { var key = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"; var valueName = "AppsUseLightTheme"; - currentLightThemeEnabled = false; + bool isLightTheme = false; using (var regKey = Registry.CurrentUser.OpenSubKey(key)) { if (regKey != null) @@ -422,11 +421,11 @@ private bool IsLightThemeEnabled() var value = regKey.GetValue(valueName); if (value != null) { - currentLightThemeEnabled = Convert.ToInt32(value) != 0; + isLightTheme = Convert.ToInt32(value) != 0; } } } - return currentLightThemeEnabled; // Default to dark theme if unable to read the registry + return isLightTheme; // Default to dark theme if unable to read the registry } private void UpdateContextMenuTheme(ContextMenuStrip contextMenu) { From 1cab395c0d66557b198caa16bc625a2b94c7c49a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:11:18 +0000 Subject: [PATCH 7/9] Cache theme update delegate to avoid allocations during theme changes Co-authored-by: lsd-techno <6795932+lsd-techno@users.noreply.github.com> --- MainForm.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/MainForm.cs b/MainForm.cs index 159f42e..a902eae 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -29,6 +29,9 @@ public partial class MainForm : Form // Track the last applied theme to avoid unnecessary reapplications private bool? lastAppliedThemeWasLight = null; + // Cached delegate for theme updates to avoid allocations + private Action? cachedThemeUpdateAction = null; + // Auto-refresh timer for network status private System.Windows.Forms.Timer autoRefreshTimer = new System.Windows.Forms.Timer(); @@ -36,6 +39,9 @@ public MainForm() { InitializeComponent(); + // Initialize cached theme update action + cachedThemeUpdateAction = ApplyThemeToMainForm; + // Apply initial theme before any other UI operations ApplyThemeToMainForm(); @@ -583,13 +589,13 @@ private void ApplyThemeToTrackBar(TrackBar trackBar, bool isLightTheme) private void OnSystemThemeChanged(object sender, Microsoft.Win32.UserPreferenceChangedEventArgs e) { - // Only respond to theme changes + // Only respond to theme changes (General category includes theme changes) if (e.Category == Microsoft.Win32.UserPreferenceCategory.General) { - // Apply the new theme + // Apply the new theme using cached delegate if (this.InvokeRequired) { - this.BeginInvoke(new Action(() => ApplyThemeToMainForm())); + this.BeginInvoke(cachedThemeUpdateAction); } else { From 73425d1fee2be53048c0da84d60c85fdd81d8dd2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:13:15 +0000 Subject: [PATCH 8/9] Simplify theme update delegate handling Co-authored-by: lsd-techno <6795932+lsd-techno@users.noreply.github.com> --- MainForm.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/MainForm.cs b/MainForm.cs index a902eae..10360d8 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -29,9 +29,6 @@ public partial class MainForm : Form // Track the last applied theme to avoid unnecessary reapplications private bool? lastAppliedThemeWasLight = null; - // Cached delegate for theme updates to avoid allocations - private Action? cachedThemeUpdateAction = null; - // Auto-refresh timer for network status private System.Windows.Forms.Timer autoRefreshTimer = new System.Windows.Forms.Timer(); @@ -39,9 +36,6 @@ public MainForm() { InitializeComponent(); - // Initialize cached theme update action - cachedThemeUpdateAction = ApplyThemeToMainForm; - // Apply initial theme before any other UI operations ApplyThemeToMainForm(); @@ -592,10 +586,10 @@ private void OnSystemThemeChanged(object sender, Microsoft.Win32.UserPreferenceC // Only respond to theme changes (General category includes theme changes) if (e.Category == Microsoft.Win32.UserPreferenceCategory.General) { - // Apply the new theme using cached delegate + // Apply the new theme if (this.InvokeRequired) { - this.BeginInvoke(cachedThemeUpdateAction); + this.BeginInvoke(ApplyThemeToMainForm); } else { From 060e8fab3d79d883e16541a8dcfb992b23ca584c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:14:35 +0000 Subject: [PATCH 9/9] Add error handling for event unsubscription in Dispose Co-authored-by: lsd-techno <6795932+lsd-techno@users.noreply.github.com> --- MainForm.Designer.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index 79a5115..2fe2840 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -19,7 +19,14 @@ protected override void Dispose(bool disposing) clickTimer?.Dispose(); // Unsubscribe from system theme changes - Microsoft.Win32.SystemEvents.UserPreferenceChanged -= OnSystemThemeChanged; + try + { + Microsoft.Win32.SystemEvents.UserPreferenceChanged -= OnSystemThemeChanged; + } + catch + { + // Ignore errors during cleanup + } } base.Dispose(disposing); }