From 2ecf8f933833fcc3f1c50314e5f264257955cc25 Mon Sep 17 00:00:00 2001
From: Xiangxin <1934109821@qq.com>
Date: Fri, 13 Feb 2026 15:53:41 +0800
Subject: [PATCH 1/5] Update TaskbarForm.cs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
传递配置参数,添加任务栏位置缓存清理函数
---
src/UI/TaskbarForm.cs | 489 +++++++++++++++++++++++++-----------------
1 file changed, 295 insertions(+), 194 deletions(-)
diff --git a/src/UI/TaskbarForm.cs b/src/UI/TaskbarForm.cs
index fa3972e..924bc1b 100644
--- a/src/UI/TaskbarForm.cs
+++ b/src/UI/TaskbarForm.cs
@@ -1,265 +1,366 @@
-using LiteMonitor.src.Core;
-using LiteMonitor.src.UI.Helpers;
+using Microsoft.Win32;
using System;
-using System.Collections.Generic;
using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
using System.Windows.Forms;
+using LiteMonitor.src.Core;
using static LiteMonitor.src.UI.Helpers.NativeMethods;
-namespace LiteMonitor
+namespace LiteMonitor.src.UI.Helpers
{
- public class TaskbarForm : Form
+ ///
+ /// 任务栏集成策略接口
+ /// 定义了不同系统版本下任务栏挂载和布局的统一行为
+ ///
+ public interface ITaskbarStrategy
+ {
+ ///
+ /// 是否准备就绪
+ ///
+ bool IsReady { get; }
+
+ ///
+ /// 挂载到任务栏
+ ///
+ void Attach(IntPtr taskbarHandle);
+
+ ///
+ /// 设置位置和大小
+ ///
+ void SetPosition(IntPtr taskbarHandle, int left, int top, int w, int h, int manualOffset, bool alignLeft);
+
+ ///
+ /// 恢复任务栏原始布局(如果做过修改)
+ ///
+ void Restore();
+
+ ///
+ /// 获取期望的父窗口句柄(用于检测是否脱离)
+ ///
+ IntPtr GetExpectedParent(IntPtr taskbarHandle);
+
+ ///
+ /// 是否拥有内部布局逻辑(如 Win10 挤占模式)
+ ///
+ bool HasInternalLayout { get; }
+ }
+
+ internal static class NativeMethods
{
+ public const int GWL_STYLE = -16;
+ public const int GWL_EXSTYLE = -20;
+ public const int WS_CHILD = 0x40000000;
+ public const int WS_VISIBLE = 0x10000000;
+ public const int WS_CLIPSIBLINGS = 0x04000000;
+ public const int WS_EX_LAYERED = 0x80000;
+ public const int WS_EX_TOOLWINDOW = 0x00000080;
+ public const uint LWA_COLORKEY = 0x00000001;
+ public const uint SWP_NOZORDER = 0x0004;
+ public const uint SWP_NOACTIVATE = 0x0010;
+ public const int WS_EX_TRANSPARENT = 0x00000020;
+ public const int DWMWA_EXTENDED_FRAME_BOUNDS = 9;
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct POINT { public int X, Y; }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT { public int left, top, right, bottom; }
+
+ [DllImport("user32.dll")] public static extern IntPtr FindWindow(string cls, string? name);
+ [DllImport("user32.dll")] public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr after, string cls, string? name);
+ [DllImport("user32.dll")] public static extern int GetWindowLong(IntPtr hWnd, int idx);
+ [DllImport("user32.dll")] public static extern int SetWindowLong(IntPtr hWnd, int idx, int value);
+ [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
+ [DllImport("user32.dll")] public static extern bool ScreenToClient(IntPtr hWnd, ref POINT pt);
+ [DllImport("user32.dll")] public static extern IntPtr SetParent(IntPtr child, IntPtr parent);
+ [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint flags);
+ [DllImport("user32.dll")] public static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
+ [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] public static extern IntPtr GetParent(IntPtr hWnd);
+ [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetForegroundWindow(IntPtr hWnd);
+ [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsWindow(IntPtr hWnd);
+ [DllImport("dwmapi.dll")] public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out RECT pvAttribute, int cbAttribute);
+ [DllImport("user32.dll")] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
+ [DllImport("user32.dll")] public static extern uint GetDpiForWindow(IntPtr hWnd);
+ }
+
+ ///
+ /// 任务栏窗口底层助手 (Windows Helper) - Facade
+ /// 职责:作为统一入口,根据系统版本委托给具体的策略 (Strategy) 处理挂载和布局
+ ///
+ public class TaskbarWinHelper
+ {
+ private readonly Form _form;
private readonly Settings _cfg;
- private readonly UIController _ui;
- private readonly MainForm _mainForm;
- private readonly System.Windows.Forms.Timer _timer = new();
+ private readonly ITaskbarStrategy _strategy;
- // ★★★ 双助手架构 ★★★
- private readonly TaskbarWinHelper _winHelper;
- private readonly TaskbarBizHelper _bizHelper;
-
- private HorizontalLayout _layout;
- private List? _cols;
- private ContextMenuStrip? _currentMenu;
- private DateTime _lastFindHandleTime = DateTime.MinValue;
- private string _lastLayoutSignature = "";
- private readonly TaskbarTooltipHelper _tooltipHelper;
-
- // 公开属性
- public string TargetDevice { get; private set; } = "";
+ // ★★★ 性能优化缓存 ★★★
+ private Rectangle _lastWindowRect = Rectangle.Empty;
+ private Rectangle _cachedResult = Rectangle.Empty;
+ private bool _isCacheValid = false;
- // 判断菜单是否打开
- public bool IsMenuOpen => _currentMenu != null && !_currentMenu.IsDisposed && _currentMenu.Visible;
-
- private const int WM_RBUTTONDOWN = 0x0204;
- private const int WM_RBUTTONUP = 0x0205;
- private const int WM_LBUTTONDBLCLK = 0x0203;
- private bool _isWin11;
+ // [Optimization] 静态缓存系统版本检测结果
+ private static readonly bool _isWin11 = Environment.OSVersion.Version.Major == 10 && Environment.OSVersion.Version.Build >= 22000;
- public TaskbarForm(Settings cfg, UIController ui, MainForm mainForm)
+ public bool UsesInternalLayout => _strategy.HasInternalLayout;
+
+ public TaskbarWinHelper(Form form, Settings cfg)
{
+ _form = form;
_cfg = cfg;
- _ui = ui;
- _mainForm = mainForm;
- TargetDevice = _cfg.TaskbarMonitorDevice;
-
- _isWin11 = Environment.OSVersion.Version >= new Version(10, 0, 22000);
-
- // 初始化组件
- _winHelper = new TaskbarWinHelper(this);
- _bizHelper = new TaskbarBizHelper(this, _cfg, _winHelper);
-
- // 窗体属性
- FormBorderStyle = FormBorderStyle.None;
- ShowInTaskbar = false;
- ControlBox = false;
- TopMost = false;
- DoubleBuffered = true;
-
- ReloadLayout();
-
- _bizHelper.CheckTheme(true);
- _bizHelper.FindHandles();
-
- _bizHelper.AttachToTaskbar();
- _winHelper.ApplyLayeredStyle(_bizHelper.TransparentKey, _cfg.TaskbarClickThrough);
-
- _timer.Interval = Math.Max(_cfg.RefreshMs, 60);
- _timer.Tick += (_, __) => Tick();
- _timer.Start();
-
- // 鼠标悬浮提示初始化
- _tooltipHelper = new TaskbarTooltipHelper(this, _cfg, _ui);
-
- Tick();
+ // 策略工厂模式:根据系统版本选择合适的集成策略
+ if (_isWin11)
+ {
+ _strategy = new TaskbarStrategyWin11(form);
+ }
+ else
+ {
+ _strategy = new TaskbarStrategyWin10(form);
+ }
}
- public void ReloadLayout()
+ // =================================================================
+ // 样式与图层
+ // =================================================================
+ public void ApplyLayeredStyle(Color transparentKey, bool clickThrough)
{
- _layout = new HorizontalLayout(ThemeManager.Current, 300, LayoutMode.Taskbar, _cfg);
- _lastLayoutSignature = ""; // 重置签名,强制重算
- _winHelper.ApplyLayeredStyle(_bizHelper.TransparentKey, _cfg.TaskbarClickThrough);
- _bizHelper.CheckTheme(true);
-
- // 更新悬浮窗模式 (支持热切换)
- _tooltipHelper?.ReloadMode();
-
- // 注意:这里仍然可能因为 _cols 为空而暂时不 Build,
- // 但随后的 Tick 会在获取到新数据后自动 Build
- if (_cols != null && _cols.Count > 0)
+ _form.BackColor = transparentKey;
+
+ if (_form.IsHandleCreated)
{
- _layout.Build(_cols, _bizHelper.Height);
- Width = _layout.PanelWidth;
- _bizHelper.UpdatePlacement(Width);
+ uint colorKey = (uint)(transparentKey.R | (transparentKey.G << 8) | (transparentKey.B << 16));
+ SetLayeredWindowAttributes(_form.Handle, colorKey, 0, LWA_COLORKEY);
}
- Invalidate();
+
+ int exStyle = GetWindowLong(_form.Handle, GWL_EXSTYLE);
+ if (clickThrough) exStyle |= WS_EX_TRANSPARENT;
+ else exStyle &= ~WS_EX_TRANSPARENT;
+ SetWindowLong(_form.Handle, GWL_EXSTYLE, exStyle);
+
+ _form.Invalidate();
}
- protected override void Dispose(bool disposing)
+ public bool IsSystemLightTheme()
{
- if (disposing)
+ try
{
- _winHelper?.RestoreTaskbar();
- _timer.Stop();
- _timer.Dispose();
- _currentMenu?.Dispose();
- _tooltipHelper?.Dispose();
+ using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
+ if (key != null)
+ {
+ object? val = key.GetValue("SystemUsesLightTheme");
+ if (val is int i) return i == 1;
+ }
}
- base.Dispose(disposing);
+ catch { }
+ return false;
}
- protected override void WndProc(ref Message m)
+ // =================================================================
+ // 挂载逻辑 (委托给策略)
+ // =================================================================
+ public void AttachToTaskbar(IntPtr taskbarHandle)
{
- // [Fix] 兼容性修复:在 Win11 25H2 + StartAllBack 环境下,
- // 右键事件会穿透到原生任务栏。
- // 因此不再区分系统版本,统一拦截右键按下和抬起消息。
- if (m.Msg == WM_RBUTTONDOWN)
- {
- return; // 吞掉按下事件,防止穿透
- }
+ _strategy.Attach(taskbarHandle);
+ }
- if (m.Msg == WM_RBUTTONUP)
- {
- this.BeginInvoke(new Action(ShowContextMenu));
- return;
- }
+ public void SetPosition(IntPtr taskbarHandle, int left, int top, int w, int h, int manualOffset = 0, bool alignLeft = true)
+ {
+ // 检查父窗口是否正确,防止脱离
+ IntPtr currentParent = GetParent(_form.Handle);
+ IntPtr expectedParent = _strategy.GetExpectedParent(taskbarHandle);
- // [Fix] 强制拦截双击事件
- // 当悬浮窗(Tooltip)显示时,WinForms 的标准双击事件可能因为焦点/激活状态的微妙变化而失效。
- // 这里直接在消息层处理 WM_LBUTTONDBLCLK,确保双击动作始终能被触发。
- if (m.Msg == WM_LBUTTONDBLCLK)
+ if (currentParent != expectedParent)
{
- _bizHelper.HandleDoubleClick(_mainForm, _ui);
- return;
+ AttachToTaskbar(taskbarHandle);
}
- base.WndProc(ref m);
+ _strategy.SetPosition(taskbarHandle, left, top, w, h, manualOffset, alignLeft);
}
- private void ShowContextMenu()
+ public void RestoreTaskbar()
{
- if (_currentMenu != null)
- {
- _currentMenu.Dispose();
- _currentMenu = null;
- }
+ _strategy.Restore();
+ }
- _currentMenu = MenuManager.Build(_mainForm, _cfg, _ui, "Taskbar");
-
- TaskbarWinHelper.ActivateWindow(this.Handle);
- _currentMenu.Show(Cursor.Position);
+ public void InvalidateCache()
+ {
+ _isCacheValid = false;
}
- protected override void OnMouseUp(MouseEventArgs e)
+ // =================================================================
+ // 句柄与信息获取 (通用逻辑)
+ // =================================================================
+ public (IntPtr hTaskbar, IntPtr hTray) FindHandles(string targetDevice)
{
- base.OnMouseUp(e);
- if (e.Button == MouseButtons.Right)
+ Screen target = Screen.PrimaryScreen;
+ if (!string.IsNullOrEmpty(targetDevice))
{
- ShowContextMenu();
+ target = Screen.AllScreens.FirstOrDefault(s => s.DeviceName == targetDevice) ?? Screen.PrimaryScreen;
}
- }
- protected override void OnMouseDoubleClick(MouseEventArgs e)
- {
- base.OnMouseDoubleClick(e);
- if (e.Button == MouseButtons.Left)
+ if (target.Primary)
{
- _bizHelper.HandleDoubleClick(_mainForm, _ui);
+ IntPtr hTaskbar = FindWindow("Shell_TrayWnd", null);
+ IntPtr hTray = FindWindowEx(hTaskbar, IntPtr.Zero, "TrayNotifyWnd", null);
+ return (hTaskbar, hTray);
+ }
+ else
+ {
+ IntPtr hTaskbar = FindSecondaryTaskbar(target);
+ return (hTaskbar, IntPtr.Zero);
}
}
- private void Tick()
+ private IntPtr FindSecondaryTaskbar(Screen screen)
{
- // [Fix] 周期性检查句柄,防止 Explorer 重启后句柄失效
- // 优化:仅在重试期或句柄无效时调用 FindHandles,且限制调用频率
- bool isHandleInvalid = !_bizHelper.IsTaskbarValid();
-
- // 如果处于重试期,或者句柄无效且距离上次查找超过2秒(防止无Explorer时高频空转)
- if (isHandleInvalid && (DateTime.Now - _lastFindHandleTime).TotalSeconds > 2)
+ IntPtr hWnd = IntPtr.Zero;
+ while ((hWnd = FindWindowEx(IntPtr.Zero, hWnd, "Shell_SecondaryTrayWnd", null)) != IntPtr.Zero)
{
- _bizHelper.FindHandles();
- _lastFindHandleTime = DateTime.Now;
+ GetWindowRect(hWnd, out RECT rect);
+ Rectangle r = Rectangle.FromLTRB(rect.left, rect.top, rect.right, rect.bottom);
+ if (screen.Bounds.Contains(r.Location) || screen.Bounds.IntersectsWith(r))
+ return hWnd;
}
+ return FindWindow("Shell_TrayWnd", null);
+ }
- if (Math.Abs(Environment.TickCount) % 5000 < _cfg.RefreshMs) _bizHelper.CheckTheme();
+ public Rectangle GetTaskbarRect(IntPtr hTaskbar, string targetDevice)
+ {
+ if (hTaskbar == IntPtr.Zero) return Rectangle.Empty;
- // [Fix Part 1] 防空数据保护
- // 使用临时变量接收,先判断数据有效性,再赋值给成员变量 _cols
- // 防止在 UI 重建期间(RebuildLayout)获取到空列表导致任务栏闪烁或清空
- var nextCols = _ui.GetTaskbarColumns();
- if (nextCols == null || nextCols.Count == 0) return;
-
- _cols = nextCols; // 确认有效后再更新引用
+ // 1. 获取物理矩形
+ if (!GetWindowRect(hTaskbar, out RECT r)) return Rectangle.Empty;
+ var rectPhys = Rectangle.FromLTRB(r.left, r.top, r.right, r.bottom);
- _bizHelper.UpdateTaskbarRect();
-
- // [Fix Part 2] 布局变更检测
- if (_bizHelper.IsVertical())
- {
- // 垂直模式逻辑简单且无测量开销,直接重算即可
- _bizHelper.BuildVerticalLayout(_cols);
- _lastLayoutSignature = "vertical";
- }
- else
- {
- // [优化] 智能判断更新条件
- // 1. 必须检查:如果列表是新生成的(坐标还没算过,Bounds为空),必须重算!
- // 这解决了“主界面显隐导致任务栏消失”的问题
- bool isUninitialized = (_cols.Count > 0 && _cols[0].Bounds.IsEmpty);
+ // 缓存检查
+ if (_isCacheValid && rectPhys == _lastWindowRect) return _cachedResult;
- // 2. 常规检查:如果内容长度/结构变了(签名变了),也要重算
- string currentSig = _layout.GetLayoutSignature(_cols) + "_" + _bizHelper.Height;
- bool isContentChanged = (currentSig != _lastLayoutSignature);
+ Rectangle finalRect = rectPhys;
+
+ // =========================================================================
+ // [SIMPLIFIED FIX] 极简稳定方案:基于 WorkingArea 和 强制高度修正 (DPI适配版)
+ // =========================================================================
+ try
+ {
+ Screen screen = null;
+ if (!string.IsNullOrEmpty(targetDevice))
+ screen = Screen.AllScreens.FirstOrDefault(s => s.DeviceName == targetDevice);
+ if (screen == null)
+ screen = Screen.FromHandle(hTaskbar);
- if (isUninitialized || isContentChanged)
+ if (screen != null)
{
- _layout.Build(_cols, _bizHelper.Height);
- Width = _layout.PanelWidth;
- Height = _bizHelper.Height;
-
- _lastLayoutSignature = currentSig;
+ Rectangle workArea = screen.WorkingArea;
+ Rectangle screenBounds = screen.Bounds;
+ int reservedBottom = screenBounds.Bottom - workArea.Bottom;
+
+ // 场景 A: 锚定模式
+ if (reservedBottom > 2)
+ {
+ finalRect = new Rectangle(rectPhys.Left, workArea.Bottom, rectPhys.Width, reservedBottom);
+ }
+ // 场景 B: 悬浮模式
+ else
+ {
+ if (_isWin11)
+ {
+ // [Fix] 增加对垂直任务栏的判断,防止误判
+ // StartAllBack 等软件可能启用垂直任务栏,此时不应应用底部水平任务栏的高度修正
+ bool isVertical = rectPhys.Height > rectPhys.Width;
+
+ if (!isVertical)
+ {
+ int dpi = GetTaskbarDpi();
+ int baseHeight = _cfg?.Win11TaskbarHeight ?? 48;
+ int standardHeight = (int)Math.Round((double)baseHeight * dpi / 96.0);
+
+ if (rectPhys.Height > (standardHeight * 0.8))
+ {
+ finalRect = new Rectangle(
+ rectPhys.Left,
+ rectPhys.Bottom - standardHeight,
+ rectPhys.Width,
+ standardHeight);
+ }
+ }
+ }
+ }
}
}
-
- _bizHelper.UpdatePlacement(Width);
-
- _tooltipHelper.UpdateContent();
+ catch { }
+
+ _lastWindowRect = rectPhys;
+ _cachedResult = finalRect;
+ _isCacheValid = true;
- Invalidate();
+ return _cachedResult;
}
- protected override void OnPaintBackground(PaintEventArgs e)
+ public bool GetWindowRectWrapper(IntPtr hWnd, out Rectangle rect)
{
- e.Graphics.Clear(_bizHelper.TransparentKey);
+ if (GetWindowRect(hWnd, out RECT r))
+ {
+ rect = Rectangle.FromLTRB(r.left, r.top, r.right, r.bottom);
+ return true;
+ }
+ rect = Rectangle.Empty;
+ return false;
}
- protected override void OnPaint(PaintEventArgs e)
+ public static bool IsCenterAligned()
{
- // ★ 调试验证用:如果消失时出现了一个红块,说明 OnPaint 被调用但 _cols 为空
- // e.Graphics.FillRectangle(Brushes.Red, 0, 0, 20, 20);
-
- if (_cols == null) return;
- var g = e.Graphics;
- g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
- g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
- g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
- TaskbarRenderer.Render(g, _cols, _bizHelper.LastIsLightTheme);
+ if (Environment.OSVersion.Version.Major < 10 || Environment.OSVersion.Version.Build < 22000)
+ return false;
+ try
+ {
+ using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced");
+ return ((int)(key?.GetValue("TaskbarAl", 1) ?? 1)) == 1;
+ }
+ catch { return false; }
}
- protected override CreateParams CreateParams
+ public static int GetTaskbarDpi()
{
- get
+ IntPtr taskbar = FindWindow("Shell_TrayWnd", null);
+ if (taskbar != IntPtr.Zero)
{
- CreateParams cp = base.CreateParams;
- cp.ExStyle |= WS_EX_LAYERED | WS_EX_TOOLWINDOW;
- cp.ExStyle |= 0x08000000; // WS_EX_NOACTIVATE (防止点击激活窗口,避免抢占焦点)
- if (_cfg != null && _cfg.TaskbarClickThrough)
- {
- cp.ExStyle |= WS_EX_TRANSPARENT;
- }
- return cp;
+ try { return (int)GetDpiForWindow(taskbar); } catch { }
}
+ return 96;
+ }
+
+ public static int GetWidgetsWidth()
+ {
+ int dpi = GetTaskbarDpi();
+ if (_isWin11)
+ {
+ string local = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ string pkg = Path.Combine(local, "Packages");
+ bool hasWidgetPkg = false;
+ try { hasWidgetPkg = Directory.GetDirectories(pkg, "MicrosoftWindows.Client.WebExperience*").Any(); } catch {}
+
+ if (!hasWidgetPkg) return 0;
+
+ using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced");
+ if (key == null) return 0;
+
+ object? val = key.GetValue("TaskbarDa");
+ if (val is int i && i != 0) return 150 * dpi / 96;
+ }
+ return 0;
+ }
+
+ public static void ActivateWindow(IntPtr handle) => SetForegroundWindow(handle);
+
+ public static bool IsWindow(IntPtr hWnd) => NativeMethods.IsWindow(hWnd);
+
+ public static void ApplyChildWindowStyle(IntPtr hWnd)
+ {
+ int style = GetWindowLong(hWnd, GWL_STYLE);
+ style &= (int)~0x80000000;
+ style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
+ SetWindowLong(hWnd, GWL_STYLE, style);
}
}
}
From 3a24b034aedcf612b505a59faf48b35cefa97373 Mon Sep 17 00:00:00 2001
From: Xiangxin <1934109821@qq.com>
Date: Fri, 13 Feb 2026 15:54:58 +0800
Subject: [PATCH 2/5] Update TaskbarForm.cs
---
src/UI/TaskbarForm.cs | 490 +++++++++++++++++-------------------------
1 file changed, 195 insertions(+), 295 deletions(-)
diff --git a/src/UI/TaskbarForm.cs b/src/UI/TaskbarForm.cs
index 924bc1b..e545ff5 100644
--- a/src/UI/TaskbarForm.cs
+++ b/src/UI/TaskbarForm.cs
@@ -1,366 +1,266 @@
-using Microsoft.Win32;
+using LiteMonitor.src.Core;
+using LiteMonitor.src.UI.Helpers;
using System;
+using System.Collections.Generic;
using System.Drawing;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
using System.Windows.Forms;
-using LiteMonitor.src.Core;
using static LiteMonitor.src.UI.Helpers.NativeMethods;
-namespace LiteMonitor.src.UI.Helpers
+namespace LiteMonitor
{
- ///
- /// 任务栏集成策略接口
- /// 定义了不同系统版本下任务栏挂载和布局的统一行为
- ///
- public interface ITaskbarStrategy
- {
- ///
- /// 是否准备就绪
- ///
- bool IsReady { get; }
-
- ///
- /// 挂载到任务栏
- ///
- void Attach(IntPtr taskbarHandle);
-
- ///
- /// 设置位置和大小
- ///
- void SetPosition(IntPtr taskbarHandle, int left, int top, int w, int h, int manualOffset, bool alignLeft);
-
- ///
- /// 恢复任务栏原始布局(如果做过修改)
- ///
- void Restore();
-
- ///
- /// 获取期望的父窗口句柄(用于检测是否脱离)
- ///
- IntPtr GetExpectedParent(IntPtr taskbarHandle);
-
- ///
- /// 是否拥有内部布局逻辑(如 Win10 挤占模式)
- ///
- bool HasInternalLayout { get; }
- }
-
- internal static class NativeMethods
+ public class TaskbarForm : Form
{
- public const int GWL_STYLE = -16;
- public const int GWL_EXSTYLE = -20;
- public const int WS_CHILD = 0x40000000;
- public const int WS_VISIBLE = 0x10000000;
- public const int WS_CLIPSIBLINGS = 0x04000000;
- public const int WS_EX_LAYERED = 0x80000;
- public const int WS_EX_TOOLWINDOW = 0x00000080;
- public const uint LWA_COLORKEY = 0x00000001;
- public const uint SWP_NOZORDER = 0x0004;
- public const uint SWP_NOACTIVATE = 0x0010;
- public const int WS_EX_TRANSPARENT = 0x00000020;
- public const int DWMWA_EXTENDED_FRAME_BOUNDS = 9;
-
- [StructLayout(LayoutKind.Sequential)]
- public struct POINT { public int X, Y; }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct RECT { public int left, top, right, bottom; }
-
- [DllImport("user32.dll")] public static extern IntPtr FindWindow(string cls, string? name);
- [DllImport("user32.dll")] public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr after, string cls, string? name);
- [DllImport("user32.dll")] public static extern int GetWindowLong(IntPtr hWnd, int idx);
- [DllImport("user32.dll")] public static extern int SetWindowLong(IntPtr hWnd, int idx, int value);
- [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
- [DllImport("user32.dll")] public static extern bool ScreenToClient(IntPtr hWnd, ref POINT pt);
- [DllImport("user32.dll")] public static extern IntPtr SetParent(IntPtr child, IntPtr parent);
- [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint flags);
- [DllImport("user32.dll")] public static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
- [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] public static extern IntPtr GetParent(IntPtr hWnd);
- [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetForegroundWindow(IntPtr hWnd);
- [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsWindow(IntPtr hWnd);
- [DllImport("dwmapi.dll")] public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out RECT pvAttribute, int cbAttribute);
- [DllImport("user32.dll")] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
- [DllImport("user32.dll")] public static extern uint GetDpiForWindow(IntPtr hWnd);
- }
-
- ///
- /// 任务栏窗口底层助手 (Windows Helper) - Facade
- /// 职责:作为统一入口,根据系统版本委托给具体的策略 (Strategy) 处理挂载和布局
- ///
- public class TaskbarWinHelper
- {
- private readonly Form _form;
private readonly Settings _cfg;
- private readonly ITaskbarStrategy _strategy;
+ private readonly UIController _ui;
+ private readonly MainForm _mainForm;
+ private readonly System.Windows.Forms.Timer _timer = new();
- // ★★★ 性能优化缓存 ★★★
- private Rectangle _lastWindowRect = Rectangle.Empty;
- private Rectangle _cachedResult = Rectangle.Empty;
- private bool _isCacheValid = false;
-
- // [Optimization] 静态缓存系统版本检测结果
- private static readonly bool _isWin11 = Environment.OSVersion.Version.Major == 10 && Environment.OSVersion.Version.Build >= 22000;
+ // ★★★ 双助手架构 ★★★
+ private readonly TaskbarWinHelper _winHelper;
+ private readonly TaskbarBizHelper _bizHelper;
+
+ private HorizontalLayout _layout;
+ private List? _cols;
+ private ContextMenuStrip? _currentMenu;
+ private DateTime _lastFindHandleTime = DateTime.MinValue;
+ private string _lastLayoutSignature = "";
+ private readonly TaskbarTooltipHelper _tooltipHelper;
+
+ // 公开属性
+ public string TargetDevice { get; private set; } = "";
- public bool UsesInternalLayout => _strategy.HasInternalLayout;
+ // 判断菜单是否打开
+ public bool IsMenuOpen => _currentMenu != null && !_currentMenu.IsDisposed && _currentMenu.Visible;
- public TaskbarWinHelper(Form form, Settings cfg)
+ private const int WM_RBUTTONDOWN = 0x0204;
+ private const int WM_RBUTTONUP = 0x0205;
+ private const int WM_LBUTTONDBLCLK = 0x0203;
+ private bool _isWin11;
+
+ public TaskbarForm(Settings cfg, UIController ui, MainForm mainForm)
{
- _form = form;
_cfg = cfg;
- // 策略工厂模式:根据系统版本选择合适的集成策略
- if (_isWin11)
- {
- _strategy = new TaskbarStrategyWin11(form);
- }
- else
- {
- _strategy = new TaskbarStrategyWin10(form);
- }
- }
+ _ui = ui;
+ _mainForm = mainForm;
+ TargetDevice = _cfg.TaskbarMonitorDevice;
- // =================================================================
- // 样式与图层
- // =================================================================
- public void ApplyLayeredStyle(Color transparentKey, bool clickThrough)
- {
- _form.BackColor = transparentKey;
-
- if (_form.IsHandleCreated)
- {
- uint colorKey = (uint)(transparentKey.R | (transparentKey.G << 8) | (transparentKey.B << 16));
- SetLayeredWindowAttributes(_form.Handle, colorKey, 0, LWA_COLORKEY);
- }
+ _isWin11 = Environment.OSVersion.Version >= new Version(10, 0, 22000);
+
+ // 初始化组件
+ _winHelper = new TaskbarWinHelper(this, _cfg);
+ _bizHelper = new TaskbarBizHelper(this, _cfg, _winHelper);
+
+ // 窗体属性
+ FormBorderStyle = FormBorderStyle.None;
+ ShowInTaskbar = false;
+ ControlBox = false;
+ TopMost = false;
+ DoubleBuffered = true;
+
+ ReloadLayout();
- int exStyle = GetWindowLong(_form.Handle, GWL_EXSTYLE);
- if (clickThrough) exStyle |= WS_EX_TRANSPARENT;
- else exStyle &= ~WS_EX_TRANSPARENT;
- SetWindowLong(_form.Handle, GWL_EXSTYLE, exStyle);
+ _bizHelper.CheckTheme(true);
+ _bizHelper.FindHandles();
- _form.Invalidate();
+ _bizHelper.AttachToTaskbar();
+ _winHelper.ApplyLayeredStyle(_bizHelper.TransparentKey, _cfg.TaskbarClickThrough);
+
+ _timer.Interval = Math.Max(_cfg.RefreshMs, 60);
+ _timer.Tick += (_, __) => Tick();
+ _timer.Start();
+
+ // 鼠标悬浮提示初始化
+ _tooltipHelper = new TaskbarTooltipHelper(this, _cfg, _ui);
+
+ Tick();
}
- public bool IsSystemLightTheme()
+ public void ReloadLayout()
{
- try
+ _winHelper?.InvalidateCache(); // 强制清除位置缓存,确保高度设置立即生效
+ _layout = new HorizontalLayout(ThemeManager.Current, 300, LayoutMode.Taskbar, _cfg);
+ _lastLayoutSignature = ""; // 重置签名,强制重算
+ _winHelper.ApplyLayeredStyle(_bizHelper.TransparentKey, _cfg.TaskbarClickThrough);
+ _bizHelper.CheckTheme(true);
+
+ // 更新悬浮窗模式 (支持热切换)
+ _tooltipHelper?.ReloadMode();
+
+ // 注意:这里仍然可能因为 _cols 为空而暂时不 Build,
+ // 但随后的 Tick 会在获取到新数据后自动 Build
+ if (_cols != null && _cols.Count > 0)
{
- using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
- if (key != null)
- {
- object? val = key.GetValue("SystemUsesLightTheme");
- if (val is int i) return i == 1;
- }
+ _layout.Build(_cols, _bizHelper.Height);
+ Width = _layout.PanelWidth;
+ _bizHelper.UpdatePlacement(Width);
}
- catch { }
- return false;
+ Invalidate();
}
- // =================================================================
- // 挂载逻辑 (委托给策略)
- // =================================================================
- public void AttachToTaskbar(IntPtr taskbarHandle)
+ protected override void Dispose(bool disposing)
{
- _strategy.Attach(taskbarHandle);
+ if (disposing)
+ {
+ _winHelper?.RestoreTaskbar();
+ _timer.Stop();
+ _timer.Dispose();
+ _currentMenu?.Dispose();
+ _tooltipHelper?.Dispose();
+ }
+ base.Dispose(disposing);
}
- public void SetPosition(IntPtr taskbarHandle, int left, int top, int w, int h, int manualOffset = 0, bool alignLeft = true)
+ protected override void WndProc(ref Message m)
{
- // 检查父窗口是否正确,防止脱离
- IntPtr currentParent = GetParent(_form.Handle);
- IntPtr expectedParent = _strategy.GetExpectedParent(taskbarHandle);
-
- if (currentParent != expectedParent)
+ // [Fix] 兼容性修复:在 Win11 25H2 + StartAllBack 环境下,
+ // 右键事件会穿透到原生任务栏。
+ // 因此不再区分系统版本,统一拦截右键按下和抬起消息。
+ if (m.Msg == WM_RBUTTONDOWN)
{
- AttachToTaskbar(taskbarHandle);
+ return; // 吞掉按下事件,防止穿透
}
- _strategy.SetPosition(taskbarHandle, left, top, w, h, manualOffset, alignLeft);
- }
+ if (m.Msg == WM_RBUTTONUP)
+ {
+ this.BeginInvoke(new Action(ShowContextMenu));
+ return;
+ }
- public void RestoreTaskbar()
- {
- _strategy.Restore();
- }
+ // [Fix] 强制拦截双击事件
+ // 当悬浮窗(Tooltip)显示时,WinForms 的标准双击事件可能因为焦点/激活状态的微妙变化而失效。
+ // 这里直接在消息层处理 WM_LBUTTONDBLCLK,确保双击动作始终能被触发。
+ if (m.Msg == WM_LBUTTONDBLCLK)
+ {
+ _bizHelper.HandleDoubleClick(_mainForm, _ui);
+ return;
+ }
- public void InvalidateCache()
- {
- _isCacheValid = false;
+ base.WndProc(ref m);
}
- // =================================================================
- // 句柄与信息获取 (通用逻辑)
- // =================================================================
- public (IntPtr hTaskbar, IntPtr hTray) FindHandles(string targetDevice)
+ private void ShowContextMenu()
{
- Screen target = Screen.PrimaryScreen;
- if (!string.IsNullOrEmpty(targetDevice))
+ if (_currentMenu != null)
{
- target = Screen.AllScreens.FirstOrDefault(s => s.DeviceName == targetDevice) ?? Screen.PrimaryScreen;
+ _currentMenu.Dispose();
+ _currentMenu = null;
}
- if (target.Primary)
- {
- IntPtr hTaskbar = FindWindow("Shell_TrayWnd", null);
- IntPtr hTray = FindWindowEx(hTaskbar, IntPtr.Zero, "TrayNotifyWnd", null);
- return (hTaskbar, hTray);
- }
- else
+ _currentMenu = MenuManager.Build(_mainForm, _cfg, _ui, "Taskbar");
+
+ TaskbarWinHelper.ActivateWindow(this.Handle);
+ _currentMenu.Show(Cursor.Position);
+ }
+
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ base.OnMouseUp(e);
+ if (e.Button == MouseButtons.Right)
{
- IntPtr hTaskbar = FindSecondaryTaskbar(target);
- return (hTaskbar, IntPtr.Zero);
+ ShowContextMenu();
}
}
- private IntPtr FindSecondaryTaskbar(Screen screen)
+ protected override void OnMouseDoubleClick(MouseEventArgs e)
{
- IntPtr hWnd = IntPtr.Zero;
- while ((hWnd = FindWindowEx(IntPtr.Zero, hWnd, "Shell_SecondaryTrayWnd", null)) != IntPtr.Zero)
+ base.OnMouseDoubleClick(e);
+ if (e.Button == MouseButtons.Left)
{
- GetWindowRect(hWnd, out RECT rect);
- Rectangle r = Rectangle.FromLTRB(rect.left, rect.top, rect.right, rect.bottom);
- if (screen.Bounds.Contains(r.Location) || screen.Bounds.IntersectsWith(r))
- return hWnd;
+ _bizHelper.HandleDoubleClick(_mainForm, _ui);
}
- return FindWindow("Shell_TrayWnd", null);
}
- public Rectangle GetTaskbarRect(IntPtr hTaskbar, string targetDevice)
+ private void Tick()
{
- if (hTaskbar == IntPtr.Zero) return Rectangle.Empty;
-
- // 1. 获取物理矩形
- if (!GetWindowRect(hTaskbar, out RECT r)) return Rectangle.Empty;
- var rectPhys = Rectangle.FromLTRB(r.left, r.top, r.right, r.bottom);
+ // [Fix] 周期性检查句柄,防止 Explorer 重启后句柄失效
+ // 优化:仅在重试期或句柄无效时调用 FindHandles,且限制调用频率
+ bool isHandleInvalid = !_bizHelper.IsTaskbarValid();
+
+ // 如果处于重试期,或者句柄无效且距离上次查找超过2秒(防止无Explorer时高频空转)
+ if (isHandleInvalid && (DateTime.Now - _lastFindHandleTime).TotalSeconds > 2)
+ {
+ _bizHelper.FindHandles();
+ _lastFindHandleTime = DateTime.Now;
+ }
- // 缓存检查
- if (_isCacheValid && rectPhys == _lastWindowRect) return _cachedResult;
+ if (Math.Abs(Environment.TickCount) % 5000 < _cfg.RefreshMs) _bizHelper.CheckTheme();
- Rectangle finalRect = rectPhys;
+ // [Fix Part 1] 防空数据保护
+ // 使用临时变量接收,先判断数据有效性,再赋值给成员变量 _cols
+ // 防止在 UI 重建期间(RebuildLayout)获取到空列表导致任务栏闪烁或清空
+ var nextCols = _ui.GetTaskbarColumns();
+ if (nextCols == null || nextCols.Count == 0) return;
+
+ _cols = nextCols; // 确认有效后再更新引用
- // =========================================================================
- // [SIMPLIFIED FIX] 极简稳定方案:基于 WorkingArea 和 强制高度修正 (DPI适配版)
- // =========================================================================
- try
+ _bizHelper.UpdateTaskbarRect();
+
+ // [Fix Part 2] 布局变更检测
+ if (_bizHelper.IsVertical())
{
- Screen screen = null;
- if (!string.IsNullOrEmpty(targetDevice))
- screen = Screen.AllScreens.FirstOrDefault(s => s.DeviceName == targetDevice);
- if (screen == null)
- screen = Screen.FromHandle(hTaskbar);
+ // 垂直模式逻辑简单且无测量开销,直接重算即可
+ _bizHelper.BuildVerticalLayout(_cols);
+ _lastLayoutSignature = "vertical";
+ }
+ else
+ {
+ // [优化] 智能判断更新条件
+ // 1. 必须检查:如果列表是新生成的(坐标还没算过,Bounds为空),必须重算!
+ // 这解决了“主界面显隐导致任务栏消失”的问题
+ bool isUninitialized = (_cols.Count > 0 && _cols[0].Bounds.IsEmpty);
+
+ // 2. 常规检查:如果内容长度/结构变了(签名变了),也要重算
+ string currentSig = _layout.GetLayoutSignature(_cols) + "_" + _bizHelper.Height;
+ bool isContentChanged = (currentSig != _lastLayoutSignature);
- if (screen != null)
+ if (isUninitialized || isContentChanged)
{
- Rectangle workArea = screen.WorkingArea;
- Rectangle screenBounds = screen.Bounds;
- int reservedBottom = screenBounds.Bottom - workArea.Bottom;
-
- // 场景 A: 锚定模式
- if (reservedBottom > 2)
- {
- finalRect = new Rectangle(rectPhys.Left, workArea.Bottom, rectPhys.Width, reservedBottom);
- }
- // 场景 B: 悬浮模式
- else
- {
- if (_isWin11)
- {
- // [Fix] 增加对垂直任务栏的判断,防止误判
- // StartAllBack 等软件可能启用垂直任务栏,此时不应应用底部水平任务栏的高度修正
- bool isVertical = rectPhys.Height > rectPhys.Width;
-
- if (!isVertical)
- {
- int dpi = GetTaskbarDpi();
- int baseHeight = _cfg?.Win11TaskbarHeight ?? 48;
- int standardHeight = (int)Math.Round((double)baseHeight * dpi / 96.0);
-
- if (rectPhys.Height > (standardHeight * 0.8))
- {
- finalRect = new Rectangle(
- rectPhys.Left,
- rectPhys.Bottom - standardHeight,
- rectPhys.Width,
- standardHeight);
- }
- }
- }
- }
+ _layout.Build(_cols, _bizHelper.Height);
+ Width = _layout.PanelWidth;
+ Height = _bizHelper.Height;
+
+ _lastLayoutSignature = currentSig;
}
}
- catch { }
-
- _lastWindowRect = rectPhys;
- _cachedResult = finalRect;
- _isCacheValid = true;
+
+ _bizHelper.UpdatePlacement(Width);
+
+ _tooltipHelper.UpdateContent();
- return _cachedResult;
+ Invalidate();
}
- public bool GetWindowRectWrapper(IntPtr hWnd, out Rectangle rect)
+ protected override void OnPaintBackground(PaintEventArgs e)
{
- if (GetWindowRect(hWnd, out RECT r))
- {
- rect = Rectangle.FromLTRB(r.left, r.top, r.right, r.bottom);
- return true;
- }
- rect = Rectangle.Empty;
- return false;
+ e.Graphics.Clear(_bizHelper.TransparentKey);
}
- public static bool IsCenterAligned()
+ protected override void OnPaint(PaintEventArgs e)
{
- if (Environment.OSVersion.Version.Major < 10 || Environment.OSVersion.Version.Build < 22000)
- return false;
- try
- {
- using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced");
- return ((int)(key?.GetValue("TaskbarAl", 1) ?? 1)) == 1;
- }
- catch { return false; }
+ // ★ 调试验证用:如果消失时出现了一个红块,说明 OnPaint 被调用但 _cols 为空
+ // e.Graphics.FillRectangle(Brushes.Red, 0, 0, 20, 20);
+
+ if (_cols == null) return;
+ var g = e.Graphics;
+ g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
+ g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
+ g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
+ TaskbarRenderer.Render(g, _cols, _bizHelper.LastIsLightTheme);
}
- public static int GetTaskbarDpi()
+ protected override CreateParams CreateParams
{
- IntPtr taskbar = FindWindow("Shell_TrayWnd", null);
- if (taskbar != IntPtr.Zero)
+ get
{
- try { return (int)GetDpiForWindow(taskbar); } catch { }
- }
- return 96;
- }
-
- public static int GetWidgetsWidth()
- {
- int dpi = GetTaskbarDpi();
- if (_isWin11)
- {
- string local = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
- string pkg = Path.Combine(local, "Packages");
- bool hasWidgetPkg = false;
- try { hasWidgetPkg = Directory.GetDirectories(pkg, "MicrosoftWindows.Client.WebExperience*").Any(); } catch {}
-
- if (!hasWidgetPkg) return 0;
-
- using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced");
- if (key == null) return 0;
-
- object? val = key.GetValue("TaskbarDa");
- if (val is int i && i != 0) return 150 * dpi / 96;
+ CreateParams cp = base.CreateParams;
+ cp.ExStyle |= WS_EX_LAYERED | WS_EX_TOOLWINDOW;
+ cp.ExStyle |= 0x08000000; // WS_EX_NOACTIVATE (防止点击激活窗口,避免抢占焦点)
+ if (_cfg != null && _cfg.TaskbarClickThrough)
+ {
+ cp.ExStyle |= WS_EX_TRANSPARENT;
+ }
+ return cp;
}
- return 0;
- }
-
- public static void ActivateWindow(IntPtr handle) => SetForegroundWindow(handle);
-
- public static bool IsWindow(IntPtr hWnd) => NativeMethods.IsWindow(hWnd);
-
- public static void ApplyChildWindowStyle(IntPtr hWnd)
- {
- int style = GetWindowLong(hWnd, GWL_STYLE);
- style &= (int)~0x80000000;
- style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
- SetWindowLong(hWnd, GWL_STYLE, style);
}
}
}
From af30343cd92bb11cd376ac6b720bfae862f9e744 Mon Sep 17 00:00:00 2001
From: Xiangxin <1934109821@qq.com>
Date: Fri, 13 Feb 2026 15:55:37 +0800
Subject: [PATCH 3/5] Add Win11 taskbar height adjustment setting
---
src/UI/Settings/TaskbarPage.cs | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/UI/Settings/TaskbarPage.cs b/src/UI/Settings/TaskbarPage.cs
index 60010df..907b4e0 100644
--- a/src/UI/Settings/TaskbarPage.cs
+++ b/src/UI/Settings/TaskbarPage.cs
@@ -160,6 +160,14 @@ private void CreateGeneralGroup()
() => Config?.TaskbarManualOffset ?? 0,
v => { if(Config!=null) Config.TaskbarManualOffset = v; });
+ // [新增] Win11 高度修正
+ if (Environment.OSVersion.Version.Major == 10 && Environment.OSVersion.Version.Build >= 22000)
+ {
+ group.AddInt(this, "Win11 任务栏高度", "px",
+ () => Config?.Win11TaskbarHeight ?? 48,
+ v => { if(Config!=null) Config.Win11TaskbarHeight = v; });
+ }
+
group.AddHint(LanguageManager.T("Menu.TaskbarAlignTip"));
AddGroupToPage(group);
}
@@ -290,4 +298,4 @@ private void AddGroupToPage(LiteSettingsGroup group)
_container.Controls.SetChildIndex(wrapper, 0);
}
}
-}
\ No newline at end of file
+}
From 16db1f19406c0f67b5756a7ce83ace787e7c601b Mon Sep 17 00:00:00 2001
From: Xiangxin <1934109821@qq.com>
Date: Fri, 13 Feb 2026 15:56:17 +0800
Subject: [PATCH 4/5] Refactor TaskbarWinHelper to include Settings and cache
invalidation
Added a Settings parameter to the TaskbarWinHelper constructor and introduced a method to invalidate the cache.
---
src/UI/Helpers/TaskbarWinHelper.cs | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/UI/Helpers/TaskbarWinHelper.cs b/src/UI/Helpers/TaskbarWinHelper.cs
index 371fcf5..924bc1b 100644
--- a/src/UI/Helpers/TaskbarWinHelper.cs
+++ b/src/UI/Helpers/TaskbarWinHelper.cs
@@ -92,6 +92,7 @@ public struct RECT { public int left, top, right, bottom; }
public class TaskbarWinHelper
{
private readonly Form _form;
+ private readonly Settings _cfg;
private readonly ITaskbarStrategy _strategy;
// ★★★ 性能优化缓存 ★★★
@@ -104,9 +105,10 @@ public class TaskbarWinHelper
public bool UsesInternalLayout => _strategy.HasInternalLayout;
- public TaskbarWinHelper(Form form)
+ public TaskbarWinHelper(Form form, Settings cfg)
{
_form = form;
+ _cfg = cfg;
// 策略工厂模式:根据系统版本选择合适的集成策略
if (_isWin11)
{
@@ -181,6 +183,11 @@ public void RestoreTaskbar()
_strategy.Restore();
}
+ public void InvalidateCache()
+ {
+ _isCacheValid = false;
+ }
+
// =================================================================
// 句柄与信息获取 (通用逻辑)
// =================================================================
@@ -265,7 +272,8 @@ public Rectangle GetTaskbarRect(IntPtr hTaskbar, string targetDevice)
if (!isVertical)
{
int dpi = GetTaskbarDpi();
- int standardHeight = (int)Math.Round(48.0 * dpi / 96.0);
+ int baseHeight = _cfg?.Win11TaskbarHeight ?? 48;
+ int standardHeight = (int)Math.Round((double)baseHeight * dpi / 96.0);
if (rectPhys.Height > (standardHeight * 0.8))
{
From 135e62e4418fba407696211e09e403692791fb9d Mon Sep 17 00:00:00 2001
From: Xiangxin <1934109821@qq.com>
Date: Fri, 13 Feb 2026 15:56:51 +0800
Subject: [PATCH 5/5] Add Win11 taskbar height property to settings
---
src/Core/Settings.cs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/Core/Settings.cs b/src/Core/Settings.cs
index a21252d..103a1e0 100644
--- a/src/Core/Settings.cs
+++ b/src/Core/Settings.cs
@@ -91,6 +91,9 @@ public class Settings
public bool TaskbarSingleLine { get; set; } = false;// 单行显示
public bool TaskbarHoverShowAll { get; set; } = true; // [新增] 悬浮显示所有监控项
public int TaskbarManualOffset { get; set; } = 0;// 手动偏移量 (像素)
+
+ // ★★★ [新增] Win11 任务栏修正高度 ★★★
+ public int Win11TaskbarHeight { get; set; } = 48; // 默认 48px (96dpi)
// ====== 任务栏:高级自定义外观 ======
public bool TaskbarCustomStyle { get; set; } = false; // 总开关